stsievert / swix

Swift Matrix Library
http://docs.stsievert.com/swix/
MIT License
593 stars 54 forks source link

Framework #31

Closed thomaskilian closed 7 years ago

thomaskilian commented 7 years ago

Hi Scott, I have done a lot of rework, and it's not complete yet. However, I like you to have a look at it. There are now two frameworks for pure OO and one with additional wrappers for functional access (not complete). There's also the test suite (adapted). Biggest changes:

So, why? Swift it not a functional language and should not be programmed that way. You are a mathematician like my wife and I know that you have quite a functional thinking (as can well be seen from your programming style). E.g instead of

arange(n)

it's now

Vector(arange:n)

Looks like more typing, but for outer access there will be the F-wrapper which allows still for the first form. So for people who are somehow used to that, there will be no difference.

There are still some issues with scoping I need to fix (as already said: Matrix allows to modify the flat vector without any check which is no good). Since the compiler allows to forbid those invalid accesses it shall be implemented. Quite some more bits and pieces I currently can't recall.

stsievert commented 7 years ago

While developing this framework, I was interested in emulating NumPy/Matlab. I'd like to stick with this approach -- I developed this this with a mathematician in mind.

I don't like polluting the global namespace with all these functions names. If we could allow the below, I'd be a fan:


using swix // or import swix, etc
var x = swix.linspace(0, 1)
thomaskilian commented 7 years ago

My intention is to use either

import SwixO 

for the OO-based or

import SwixF

for the functional framework. This basically works (though it's not completely implemented by now). With the latter you can use functions like arange(7) or SwixF.arange(7) and the like as you know it. When importing the first you would have a rather strong encapsulation of functions (i.e. all vector-related operations would be part of Vector, ditto for matrix).

thomaskilian commented 7 years ago

You can achieve the above in two ways. Either you compile and test the framework and then copy the frameworks to /Library/Frameworks from where you can use them in other projects. Or you add Swix as sub-project and link that.

stsievert commented 7 years ago

I'd be most inclined to follow the Swift Package Manager -- I don't like the overhead of adding extra complexity by introducing two different frameworks.

Looking at their docs, it looks like functions are imported into the global namespace. I'd look into this to verify this is the case, and if it is we could throw all the functions inside a wrapper.

thomaskilian commented 7 years ago

Actually there is no complexity in having two frameworks. It's just that the one includes the wrapper module and the other doesn't.

thomaskilian commented 7 years ago

I guess, I'm done for this step. You can build and test both frameworks with this project now. As said you can then use the framework with import SwixF so you can use the functions as you know it. I can think about renaming the F-parts to just Swix (there was a name conflict with the project name which made me choose the F/O suffixes).

thomaskilian commented 7 years ago

Scott, I have a couple of other issues and don't know where to put them. So I place them here for the time being. When creating a vector in NumPy it's data type seems to be fixed during creation time. E.g.

a=np.array([[1,2]])
a += 1.1

[[2 3]]

while

a=np.array([[1.1,2]])
a += 1.1

[[ 2.2 3.1]]

Since your intention is to mimic NumPy, this should probably also be handled in Swix the same way?

thomaskilian commented 7 years ago

I made a couple of test. Swift simply sucks. Each operation will copy the whole vectors per value, not per reference. Python is by factors faster than Swift this way. An interpreter language! This is simply a ridiculous lame language the Apple guys invented. My 14 year old son could have done better.

thomaskilian commented 7 years ago

Even worse:

public func + (lhs: Vector, rhs: Vector) -> Vector{ return make_operator(lhs, operation: .add, rhs: rhs)}

can not be re-written to reuse the exiting result vector. It will always allocate a new vector and the throw away the existing one. E.g.

vec = Vector(zeros:10) // allocates 40 bytes+ for the vector
vec = vec + vec // see below

The addition will make two physical copies of vec on the call stack for make_operator. This will first allocate a new result vector. Then the (fast) internal computation is made. The final assignment will then copy the allocated result vector back to vec and dispose it. Since you can not access the left hand side of an assignment in operator function, you are lost. You are doomed to use something like

make_operation(&vec, &vec, "+", &vec)

as Vector is a struct. Re-defining it as class can save you the & but you would never generate performant code with

vec = vec + vec

OMG, what a fail. I'll give Swift a kick in it's rear.