|
QuickStart
Getting stated in Scalala in ten minutes
Getting started in Scalala in ten minutesBuilding ScalalaCheck 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 consoleOpen 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 MatricesScalala 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
0The 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
0You 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 0Assignments 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 sizesElements 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.5000The 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.0000Operator expressionsScalala 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.2900Matrix 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.0000And 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.5000Exploring the standard libraryScalala 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")
ConclusionNow 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