My favorites | Sign in
Project Logo
                
Search
for
Updated Jun 29, 2009 by dramage
QuickStart  
Getting stated in Scalala in ten minutes

Getting started in Scalala in ten minutes

Building Scalala

Check out Scalala from the git repository at scalanlp.org or from the svn mirror. You'll need Scala and Ant or Maven2. From the root of the checkout, run:

mvn compile

or

export SCALA_HOME=/path/to/scala; ant compile

Some scala compiler bugs prevent Scalala from building correctly off a partial build, so if you have any issues try running ant clean compile. If you get a StackOverflowError or OutOfMemoryError while compiling with ant, you might need to give ant more memory. Try running export ANT_OPTS=-Xmx1g before running ant.

The root checkout is also a configured Eclipse project using the Scala eclipse plugin, so the checkout can be imported as an existing project into a properly configured eclipse workspace.

The Scalala console

Open up the Scalala console by running:

mvn scala:console or sh ./scalala.sh

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

import scalala.Scalala._;
import scalala.tensor.{Tensor,Tensor1,Tensor2,Vector,Matrix};
import scalala.tensor.dense.{DenseVector,DenseMatrix};
import scalala.tensor.sparse._;

The object scalala.Scalala contains the full Scalala environment, which is a mix-in of all the traits in the scalala.library package (following Scala's "cake" pattern), and the remaining imports are the basic Vector and Matrix data types. The following sections give a flavor of Scalala can do with a console-driven walk-through.

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 double values at positions indexed by one or more integers. Vector extends Tensor[Int] because it is indexed by a single Int whereas Matrix extends Tensor[(Int,Int)] because it is indexed by a row and column offset.

First, let's request a dense vector of zeros using a constructor method in scalala.Scalala:

scala> val x = DenseVector(5)(0)
x: scalala.tensor.dense.DenseVector = 
     0
     0
     0
     0
     0

The DenseVector constructor accepts two arguments, a size and a default value (or, alternatively, a list of values to use). The vector object supports accessing and updating double valued data elements by their index in 0 to x.size-1. We've created a vector that represents its values in a "dense" Array[Double], i.e. memory is allocated for each index. We could as well have created a SparseVector(10)(0), which does not allocate memory for default values.

scala> x(0)
res0: Double = 0.0

scala> x(1) = 2

scala> x(1)
res2: Double = 2.0

scala> x
res3: scalala.tensor.dense.DenseVector = 
     0
     2
     0
     0
     0

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

scala> x(3 to 4) = .5

scala> x
res5: scalala.tensor.dense.DenseVector = 
        0
   2.0000
        0
   0.5000
   0.5000


scala> x(0 until x.size)
res6: Seq[Double] = RangeM(0.0, 2.0, 0.0, 0.5, 0.5)

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

scala> val m = DenseMatrix(5,5)(0)
m: scalala.tensor.dense.DenseMatrix = 
     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
res8: scalala.tensor.dense.DenseMatrix = 
     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


scala> m(List((2,0),(2,1),(2,2)))
res9: Seq[Double] = List(0.0, 3.0, 0.0)

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

scala> (m.rows, m.cols)
res10: (Int, Int) = (5,5)

scala> m.getCol(1)(0 until m.rows)
res11: Seq[Double] = RangeM(0.0, 0.0, 3.0, 0.0, 0.0)

Any tensor can have its value assigned from another tensor defined on a compatible domain (same size or number of rows and columns) using the := assignment operator.

scala> m.getCol(3) := x // ":=" is Scalala's assignment operator

scala> m
res13: scalala.tensor.dense.DenseMatrix = 
        0        0        0        0        0
        0        0        0   2.0000        0
        0   3.0000        0        0        0
        0        0        0   0.5000        0
        0        0        0   0.5000        0

Assignments with incompatible cardinality won't compile (with a disappointingly meaningless error message), and assignments with incompatible size will throw a DomainException:

scala> m := DenseVector(5)(0)
<console>:10: error: type mismatch;
 found   : scalala.tensor.dense.DenseVector
 required: scalala.collection.PartialMap[(Int, Int),Double]
       m := DenseVector(5)(0)
            ^

scala> m := DenseMatrix(3,3)(0)
scalala.collection.domain.DomainException: Incompatible domain sizes

Elements of a tensor can be updated with standard operators:

scala> x(0) += .01

scala> x
res16: scalala.tensor.dense.DenseVector = 
   0.0100
   2.0000
        0
   0.5000
   0.5000

The tensor as a whole can also be updated by a scalar or by another tensor with compatible domain. 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 (like matlab's "."). Note that because :+= and :-= are defined element-wise, the colon is optional. The scalar operator :^= is prefixed with a colon to disambiguate from (square) matrix exponentiation.

scala> x += 1

scala> x :*= Vector(-2,-1,0,1,2) // Vector(values : Double*) is a Vector literal

scala> x
res20: scalala.tensor.dense.DenseVector = 
  -2.0200
  -3.0000
        0
   1.5000
   3.0000

Operator expressions

Scalala supports a rich library of operators defined on vectors and matrices using implicit type promotion to scalala.tensor.operators.TensorOp. Tensors can be composed with scalar updates + - * / :^ or with other tensors with compatible domain using :+ :- :* :/ :^. Comparison operators (:== :!= < :< > :> <= :<= >= :>= && :&& || :||) also exist, which create binary vectors. Again, the ":" prefix for :+ :- and the comparison operators can be left out, (except for == and != which have special meaning in terms of .equals in Scala). * and \ are also supported as matrix-vector or matrix-matrix operations.

scala> m * x
MatrixMultColVector(
  TensorIdentity(        0        0        0        0        0
                         0        0        0   2.0000        0
                         0   3.0000        0        0        0
                         0        0        0   0.5000        0
                         0        0        0   0.5000        0),
  TensorIdentity(  -2.0200
                   -3.0000
                         0
                    1.5000
                    3.0000))

Constructing an operator is a lightweight operation and does not actually compute the value of the result immediately. The reason is so that arithmetic expressions can be composed before being evaluated, as special-purpose numerical optimizations provided by linear algebra backends like BLAS and LAPACK sometimes require more than two arguments. An operator can be assigned to a tensor with a compatible domain using := or can be evaluated into its own new tensor allocation by calling its .value method.

scala> m * x value
res21: scalala.tensor.dense.DenseVector = 
        0
   3.0000
  -9.0000
   0.7500
   0.7500

scala> (m + 2) * x value
res22: scalala.tensor.dense.DenseVector = 
   -1.0400
    1.9600
  -10.0400
   -0.2900
   -0.2900

Matrix and vector transposes are operators, too, that can be accessed with the ".t" method:

scala> x
res35: scalala.tensor.dense.DenseVector = 
  -2.0200
  -3.0000
        0
   1.5000
   3.0000

scala> x.t * x
res36: Double = 24.3304

scala> x * x.t value
res37: scalala.tensor.dense.DenseMatrix = 
   4.0804  -6.0600        0  -3.0300  -6.0600
  -6.0600   9.0000        0   4.5000   9.0000
        0        0        0        0        0
  -3.0300   4.5000        0   2.2500   4.5000
  -6.0600   9.0000        0   4.5000   9.0000

And systems of equations can be solved using the "\" operator:

scala> eye(5) // like matlab's eye command
res60: scalala.tensor.dense.DenseMatrix = 
     1     0     0     0     0
     0     1     0     0     0
     0     0     1     0     0
     0     0     0     1     0
     0     0     0     0     1


scala> (m + eye(5)) \ x value 
res59: scalala.tensor.dense.DenseVector = 
   -2.0200
   -5.0000
   15.0000
    1.0000
    2.5000

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 (ant scaladoc) 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 = linspace(0,1);
plot(x, x :^ 2)
hold(true)
plot(x, x :^ 3, '.')
xlabel("x axis")
ylabel("y axis")
saveas("lines.png") // save current figure as a .png, eps and pdf also supported

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(randn(1000000),100)
title("A normal distribution")
saveas("subplots.png")

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

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

Conclusion

Now that you know the basics, enjoy playing with Scalala. Please send questions or comments to the Scalala google group.


Sign in to add a comment
Hosted by Google Code