scalanlp/breeze — pull request #278 by gabeos (2014-07-17 21:55:06+00:00)
Title: Feature/algebra

Okay, this is a pretty large refactoring of the VectorSpace and NumericOps hierarchies. I only intended to make some small changes, but it kind of snowballed and then I just kind of went for it.. It basically just provides more granularity for the VectorSpaces and NumericOps, and implements all the changes that necessitate and result from those throughout the codebase. Sorry if it's too big a change, but It doesn't actually change functionality very much, and should make some extensions easier. Let me know what you think :)

Major changes:

* VectorSpace Hierarchy
+ Refactored roughly as follows:
MutableMod <- MutableNormMod <- MutableInnProdMod <- MutableVectorRing
v v v v
Space <- Module <- Normed Module <- InnerProductModule <- VectorRing
^ ^ ^ ^
VectorSpace <- NormedVS <- InnerProdVS <- VectorField
^ ^ ^ ^
MutableVS <- MutableNormVS <- MutableInnProdVS <- MutableVectorField

My ascii art is bad, but roughly, there are:
Modules over scalar Rings
VectorSpaces over scalar Fields
VectorRings, which are Rings of Vectors (or Matrices) with Ring elements under element-wise addition and multiplication
VectorFields, which are Fields of Vectors with Field elements under element-wise addition, multiplication, inversion
Plus the Mutable, Normed, InnerProduct variants.

The idea is that this allows for the Optimization algorithms to declare exactly what types of operations they will need through the implicit they require, which will hopefully ease the burden of getting optimization for a new data type.

* Refactored NumericOps
+ Basically along the lines of the above VectorSpace hierarchy so that each space only provides the usable operations. Still have a NumericOps type that includes all of the original operations.

* New implicit space "makers" for each datatype that works over Fields rather than each individual type
* Added some new implicits, norms, etc. that operate over Fields rather than using @expand for each basic type.
* Added canCreateZeros, which takes an argument of the Key type for the tensor which is the dimensionality of the tensor, and gives you a zeros tensor of that dim. Note that this is not particularly sensible for some implicitly full-dimensional tensors, such as Counters, which should not require a key type argument to give you a zero Counter. It's left like this mostly because changing it would require jumping through a bunch of hoops: more VectorSpaces, weird implicits to make sure that you can call a VS.zeros with no arguments and get something of the dimensionality that you want. Basically, it would mean you only get a VectorSpace when you have a vector in scope, which uglifies the optimization code by requiring that you import the space implicits every time you need them rather than just at the top level. Maybe also would be slower because you'd have to make the space each time a function is called.
* Added "dim" UFunc, which should work roughly like Numpy Mat.shape, giving you an (Int,Int) for matrices, and an Int for vectors. Not fully implemented across all types. Not sure if this is necessary or good, I did it when I was playing around with the canCreateZeros issue above, and thought it might be worthwhile.
* Updated MutablizingAdaptor for new VectorSpaces
* Updated all Optimization code with appropriate VectorSpaces
* Updated Tests

Todo/other:
* In line with these changes, now I believe Int can be refactored as a Ring rather than a Field, and still allow for most of the optimization code to work with Vector[Int].
* If you have any thoughts on how to solve the createZeros dilemma above, I'd love some input, I couldn't figure it out reasonably
* Was thinking that another positive change would be to make the Semiring/Ring/Field hierarchy work with implicits and NumericOps, which could slim down the VectorSpaces a bit by allowing VectorRing/VectorField to actually be expressed as Field[Vector[E:Field]]