Showing:

0

37

1mo ago

2

0

BSD-3-Clause

# Matft

Matft is Numpy-like library in Swift. Function name and usage is similar to Numpy.

Note: You can use Protocol version(beta version) too.

## Feature & Usage

• Many types

• Pretty print

• Indexing

• Positive
• Negative
• Boolean
• Fancy
• Slicing

• Start / To / By
• New Axis
• View

• Assignment
• Conversion

• Transpose
• Reshape
• Astype
• Univarsal function reduction

• Mathematic

• Arithmetic
• Statistic
• Linear Algebra

...etc.

See Function List for all functions.

### Declaration

#### MfArray

• The MfArray such like a numpy.ndarray

``````let a = MfArray([[[ -8,  -7,  -6,  -5],
[ -4,  -3,  -2,  -1]],

[[ 0,  1,  2,  3],
[ 4,  5,  6,  7]]])
let aa = Matft.arange(start: -8, to: 8, by: 1, shape: [2,2,4])
print(a)
print(aa)
/*
mfarray =
[[[ -8,     -7,     -6,     -5],
[   -4,     -3,     -2,     -1]],

[[  0,      1,      2,      3],
[   4,      5,      6,      7]]], type=Int, shape=[2, 2, 4]
mfarray =
[[[ -8,     -7,     -6,     -5],
[   -4,     -3,     -2,     -1]],

[[  0,      1,      2,      3],
[   4,      5,      6,      7]]], type=Int, shape=[2, 2, 4]
*/
``````

#### MfType

• You can pass MfType as MfArray's argument `mftype: .Hoge `. It is similar to `dtype`.

※Note that stored data type will be Float or Double only even if you set MfType.Int. So, if you input big number to MfArray, it may be cause to overflow or strange results in any calculation (+, -, *, /,... etc.). But I believe this is not problem in practical use.

• MfType's list is below

``````public enum MfType: Int{
case None // Unsupportted
case Bool
case UInt8
case UInt16
case UInt32
case UInt64
case UInt
case Int8
case Int16
case Int32
case Int64
case Int
case Float
case Double
case Object // Unsupported
}
``````
• Also, you can convert MfType easily using `astype`

``````let a = MfArray([[[ -8,  -7,  -6,  -5],
[ -4,  -3,  -2,  -1]],

[[ 0,  1,  2,  3],
[ 4,  5,  6,  7]]])
print(a)//See above. if mftype is not passed, MfArray infer MfType. In this example, it's MfType.Int

let a = MfArray([[[ -8,  -7,  -6,  -5],
[ -4,  -3,  -2,  -1]],

[[ 0,  1,  2,  3],
[ 4,  5,  6,  7]]], mftype: .Float)
print(a)
/*
mfarray =
[[[ -8.0,       -7.0,       -6.0,       -5.0],
[   -4.0,       -3.0,       -2.0,       -1.0]],

[[  0.0,        1.0,        2.0,        3.0],
[   4.0,        5.0,        6.0,        7.0]]], type=Float, shape=[2, 2, 4]
*/
let aa = MfArray([[[ -8,  -7,  -6,  -5],
[ -4,  -3,  -2,  -1]],

[[ 0,  1,  2,  3],
[ 4,  5,  6,  7]]], mftype: .UInt)
print(aa)
/*
mfarray =
[[[ 4294967288,     4294967289,     4294967290,     4294967291],
[   4294967292,     4294967293,     4294967294,     4294967295]],

[[  0,      1,      2,      3],
[   4,      5,      6,      7]]], type=UInt, shape=[2, 2, 4]
*/
//Above output is same as numpy!
/*
>>> np.arange(-8, 8, dtype=np.uint32).reshape(2,2,4)
array([[[4294967288, 4294967289, 4294967290, 4294967291],
[4294967292, 4294967293, 4294967294, 4294967295]],

[[         0,          1,          2,          3],
[         4,          5,          6,          7]]], dtype=uint32)
*/

print(aa.astype(.Float))
/*
mfarray =
[[[ -8.0,       -7.0,       -6.0,       -5.0],
[   -4.0,       -3.0,       -2.0,       -1.0]],

[[  0.0,        1.0,        2.0,        3.0],
[   4.0,        5.0,        6.0,        7.0]]], type=Float, shape=[2, 2, 4]
*/
``````

### Subscription

#### MfSlice

• You can access specific data using subscript.

You can set MfSlice (see below's list) to subscript.

• ``````MfSlice(start: Int? = nil, to: Int? = nil, by: Int = 1)
``````
• ``````Matft.newaxis
``````
• ``````~< //this is prefix, postfix and infix operator. same as python's slice, ":"
``````

#### (Positive) Indexing

• Normal indexing

``````let a = Matft.arange(start: 0, to: 27, by: 1, shape: [3,3,3])
print(a)
/*
mfarray =
[[[ 0,      1,      2],
[   3,      4,      5],
[   6,      7,      8]],

[[  9,      10,     11],
[   12,     13,     14],
[   15,     16,     17]],

[[  18,     19,     20],
[   21,     22,     23],
[   24,     25,     26]]], type=Int, shape=[3, 3, 3]
*/
print(a[2,1,0])
// 21
``````

#### Slicing

• If you replace `:` with `~<`, you can get sliced mfarray. Note that use `a[0~<]` instead of `a[:]` to get all elements along axis.

``````print(a[~<1])  //same as a[:1] for numpy
/*
mfarray =
[[[ 9,      10,     11],
[   12,     13,     14],
[   15,     16,     17]]], type=Int, shape=[1, 3, 3]
*/
print(a[1~<3]) //same as a[1:3] for numpy
/*
mfarray =
[[[ 9,      10,     11],
[   12,     13,     14],
[   15,     16,     17]],

[[  18,     19,     20],
[   21,     22,     23],
[   24,     25,     26]]], type=Int, shape=[2, 3, 3]
*/
print(a[~<~<2]) //same as a[::2] for numpy
//print(a[~<<2]) //alias
/*
mfarray =
[[[ 0,      1,      2],
[   3,      4,      5],
[   6,      7,      8]],

[[  18,     19,     20],
[   21,     22,     23],
[   24,     25,     26]]], type=Int, shape=[2, 3, 3]
*/
``````

#### Negative Indexing

• Negative indexing is also available That's implementation was hardest for me...

``````print(a[~<-1])
/*
mfarray =
[[[ 0,      1,      2],
[   3,      4,      5],
[   6,      7,      8]],

[[  9,      10,     11],
[   12,     13,     14],
[   15,     16,     17]]], type=Int, shape=[2, 3, 3]
*/
print(a[-1~<-3])
/*
mfarray =
[], type=Int, shape=[0, 3, 3]
*/
print(a[~<~<-1])
//print(a[~<<-1]) //alias
/*
mfarray =
[[[ 18,     19,     20],
[   21,     22,     23],
[   24,     25,     26]],

[[  9,      10,     11],
[   12,     13,     14],
[   15,     16,     17]],

[[  0,      1,      2],
[   3,      4,      5],
[   6,      7,      8]]], type=Int, shape=[3, 3, 3]*/
``````

#### Boolean Indexing

• You can use boolean indexing.

Caution! I don't check performance, so this boolean indexing may be slow

Unfortunately, Matft is too slower than numpy...

(numpy is 1ms, Matft is 7ms...)

``````let img = MfArray([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], mftype: .UInt8)
img[img > 3] = MfArray([10], mftype: .UInt8)
print(img)
/*
mfarray =
[[  1,      2,      3],
[   10,     10,     10],
[   10,     10,     10]], type=UInt8, shape=[3, 3]
*/
``````

#### Fancy Indexing

• You can use fancy indexing!!!

``````let a = MfArray([[1, 2], [3, 4], [5, 6]])

a[MfArray([0, 1, 2]), MfArray([0, -1, 0])] = MfArray([999,888,777])
print(a)
/*
mfarray =
[[  999,        2],
[   3,      888],
[   777,        6]], type=Int, shape=[3, 2]
*/

a.T[MfArray([0, 1, -1]), MfArray([0, 1, 0])] = MfArray([-999,-888,-777])
print(a)
/*
mfarray =
[[  -999,       -777],
[   3,      -888],
[   777,        6]], type=Int, shape=[3, 2]
*/
``````

#### View

• Note that returned subscripted mfarray will have `base` property (is similar to `view` in Numpy). See numpy doc in detail.

``````let a = Matft.arange(start: 0, to: 4*4*2, by: 1, shape: [4,4,2])

let b = a[0~<, 1]
b[~<<-1] = MfArray([9999]) // cannot pass Int directly such like 9999

print(a)
/*
mfarray =
[[[ 0,      1],
[   9999,       9999],
[   4,      5],
[   6,      7]],

[[  8,      9],
[   9999,       9999],
[   12,     13],
[   14,     15]],

[[  16,     17],
[   9999,       9999],
[   20,     21],
[   22,     23]],

[[  24,     25],
[   9999,       9999],
[   28,     29],
[   30,     31]]], type=Int, shape=[4, 4, 2]
*/
``````

## Function List

Below is Matft's function list. As I mentioned above, almost functions are similar to Numpy. Also, these function use Accelerate framework inside, the perfomance may keep high.

* means method function exists too. Shortly, you can use `a.shallowcopy()` where `a` is `MfArray`.

^ means method function only. Shortly, you can use `a.tolist()` not `Matft.tolist` where `a` is `MfArray`.

• Creation
MatftNumpy
*Matft.shallowcopy*numpy.copy
*Matft.deepcopycopy.deepcopy
Matft.numsnumpy.ones * N
Matft.nums_likenumpy.ones_like * N
Matft.arangenumpy.arange
Matft.eyenumpy.eye
Matft.diagnumpy.diag
Matft.vstacknumpy.vstack
Matft.hstacknumpy.hstack
Matft.concatenatenumpy.concatenate
*Matft.appendnumpy.append
*Matft.insertnumpy.insert
*Matft.takenumpy.take
• Conversion
MatftNumpy
*Matft.astype*numpy.astype
*Matft.transpose*numpy.transpose
*Matft.expand_dims*numpy.expand_dims
*Matft.squeeze*numpy.squeeze
*Matft.conv_order*numpy.ascontiguousarray
*Matft.flatten*numpy.flatten
*Matft.flip*numpy.flip
*Matft.clip*numpy.clip
*Matft.swapaxes*numpy.swapaxes
*Matft.moveaxis*numpy.moveaxis
*Matft.sort*numpy.sort
*Matft.argsort*numpy.argsort
^MfArray.toArray^numpy.ndarray.tolist
^MfArray.toFlattenArrayn/a
*Matft.orderedUniquenumpy.unique
• File
MatftNumpy
Matft.file.genfromtxtnumpy.genfromtxt
Matft.file.savetxtnumpy.savetxt
• Operation

Line 2 is infix (prefix) operator.

MatftNumpy
+
+
Matft.sub
-
numpy.sub
-
Matft.div
/
numpy.div
.
Matft.mul
*
numpy.multiply
*
Matft.inner
*+
numpy.inner
n/a
Matft.cross
*^
numpy.cross
n/a
Matft.matmul
*&
numpy.matmul
@
Matft.equal
===
numpy.equal
==
Matft.not_equal
!==
numpy.not_equal
!=
Matft.less
<
numpy.less
<
Matft.less_equal
<=
numpy.less_equal
<=
Matft.greater
>
numpy.greater
>
Matft.greater_equal
>=
numpy.greater_equal
>=
Matft.allEqual
==
numpy.array_equal
n/a
Matft.neg
-
numpy.negative
-
• Universal Fucntion Reduction
MatftNumpy
*Matft.ufuncReduce
*Matft.ufuncAccumulate
• Math function
MatftNumpy
Matft.math.sinnumpy.sin
Matft.math.asinnumpy.asin
Matft.math.sinhnumpy.sinh
Matft.math.asinhnumpy.asinh
Matft.math.sinnumpy.cos
Matft.math.acosnumpy.acos
Matft.math.coshnumpy.cosh
Matft.math.acoshnumpy.acosh
Matft.math.tannumpy.tan
Matft.math.atannumpy.atan
Matft.math.tanhnumpy.tanh
Matft.math.atanhnumpy.atanh
Matft.math.sqrtnumpy.sqrt
Matft.math.rsqrtnumpy.rsqrt
Matft.math.expnumpy.exp
Matft.math.lognumpy.log
Matft.math.log2numpy.log2
Matft.math.log10numpy.log10
*Matft.math.ceilnumpy.ceil
*Matft.math.floornumpy.floor
*Matft.math.truncnumpy.trunc
*Matft.math.nearestnumpy.nearest
*Matft.math.roundnumpy.round
Matft.math.absnumpy.abs
Matft.math.reciprocalnumpy.reciprocal
Matft.math.powernumpy.power
Matft.math.squarenumpy.square
Matft.math.signnumpy.sign
• Statistics function
MatftNumpy
*Matft.stats.mean*numpy.mean
*Matft.stats.max*numpy.max
*Matft.stats.argmax*numpy.argmax
*Matft.stats.min*numpy.min
*Matft.stats.argmin*numpy.argmin
*Matft.stats.sum*numpy.sum
Matft.stats.maximumnumpy.maximum
Matft.stats.minimumnumpy.minimum
*Matft.stats.sumsqrtn/a
*Matft.stats.squaresumn/a
*Matft.stats.cumsum*numpy.cumsum
• Random function
MatftNumpy
Matft.random.randnumpy.random.rand
Matft.random.randintnumpy.random.randint
• Linear algebra
MatftNumpy
Matft.linalg.solvenumpy.linalg.solve
Matft.linalg.invnumpy.linalg.inv
Matft.linalg.detnumpy.linalg.det
Matft.linalg.eigennumpy.linalg.eig
Matft.linalg.svdnumpy.linalg.svd
Matft.linalg.pinvnumpy.linalg.pinv
Matft.linalg.polar_leftscipy.linalg.polar
Matft.linalg.polar_rightscipy.linalg.polar
Matft.linalg.normlp_vecscipy.linalg.norm
Matft.linalg.normfro_matscipy.linalg.norm
Matft.linalg.normnuc_matscipy.linalg.norm
• Interpolation

Matft supports only natural cubic spline. I'll implement other boundary condition later.

MatftNumpy
Matft.interp1d.cubicSplinescipy.interpolation.CubicSpline

## Performance

I use `Accelerate` framework, so all of MfArray operation may keep high performance.

``````let a = Matft.arange(start: 0, to: 10*10*10*10*10*10, by: 1, shape: [10,10,10,10,10,10])
let aneg = Matft.arange(start: 0, to: -10*10*10*10*10*10, by: -1, shape: [10,10,10,10,10,10])
let aT = a.T
let b = a.transpose(axes: [0,3,4,2,1,5])
let c = a.transpose(axes: [1,2,3,4,5,0])
let posb = a > 0
``````
``````import numpy as np

a = np.arange(10**6).reshape((10,10,10,10,10,10))
aneg = np.arange(0, -10**6, -1).reshape((10,10,10,10,10,10))
aT = a.T
b = a.transpose((0,3,4,2,1,5))
c = a.transpose((1,2,3,4,5,0))
posb = a > 0
``````
• Arithmetic test
`let _ = a+aneg``863μs``a+aneg``1.04ms`
`let _ = b+aT``4.47ms``b+aT``4.31ms`
`let _ = c+aT``5.30ms``c+aT``2.92ms`
• Math test
`let _ = Matft.math.sin(a)``1.80ms``np.sin(a)``14.7ms`
`let _ = Matft.math.sin(b)``8.24ms``np.sin(b)``15.8ms`
`let _ = Matft.math.sign(a)``30.4ms``np.sign(a)``1.37ms`
`let _ = Matft.math.sign(b)``35.6ms``np.sign(b)``1.42ms`
• Bool test
`let _ = a > 0``7.27ms``a > 0``855μs`
`let _ = a > b``13.3ms``a > b``1.83ms`
`let _ = a === 0``9.91ms``a == 0``603μs`
`let _ = a === b``22.3ms``a == b``1.78ms`
• Indexing test
`let _ = a[posb]``1.07ms``a[posb]``1.29ms`

Matft achieved almost same performance as Numpy!!!

※Swift's performance test was conducted in release mode

However, as you can see the above table, Matft's boolean operation is toooooooo slow...(Issue #18)

So, a pull request is very welcome!!

## Installation

Caution: I strongly recommend to use SwiftPM!!

### SwiftPM

• Import
• Project > Build Setting > +
• Select Rules
• Update
• File >Swift Packages >Update to Latest Package versions

### Carthage

• Set Cartfile

``````echo 'github "jjjkkkjjj/Matft"' > Cartfile
carthage update ###or append '--platform ios'
``````

### CocoaPods

• Create Podfile (Skip if you have already done)

``````pod init
``````
• Write `pod 'Matft'` in Podfile such like below

``````target 'your project' do
pod 'Matft'
end
``````
• Install Matft

``````pod install
``````

## Rate & Review

Great Documentation0
Easy to Use0
Performant0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Slow0
Buggy0
Abandoned0
Unwelcoming Community0
100