Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

jjjkkkjjj
jjjkkkjjj

Posted on

     

The matrix operation library in Swift

This post is first for me, nice to meet you!

In this post, I’d like to introduceMatft library in swift to you.

Here is the source code link.

AboutMatft

Matft is easy and fast to operate vector, matrix, tensor(N dimensional array), and even complex and image data!
The nameMatft comes frommat-rix operation library in swi-ft.
If you are accustomed to usingNumpy in python,Matft will be the best option to achieve your matrix operation becauseMatft's function names are similar toNumpy's ones. (I'll show the examples later)
ManyNumpy's functions has already implemented inMatft.

You can operate complex number asNumpy can, and there is conversion function that convertsCGImage intoMfArray (Matft's object of n-dimensional array) vice versa.

Also, becauseMatft uses theAccelerate framework (link),Matft keeps high performance (some functions even achieves higher thanNumpy).

That's why I recommend to useMatft when you'd like to operate vector, matrix, tensor(N dimensional array), and even complex and image data

Basic usage

MfType

Matft's object to operate n-dimensional array is namedMfArray inMatft. AndMfArray hasmftype property topretend the n-dimensional array's type. (=Numpy's dtype)

Pretending means that the stored data type will beFloat orDouble only even if you setMfType.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 supports many types such like;

publicenumMfType:Int{caseNone// UnsupporttedcaseBoolcaseUInt8caseUInt16caseUInt32caseUInt64caseUIntcaseInt8caseInt16caseInt32caseInt64caseIntcaseFloatcaseDoublecaseObject// Unsupported}
Enter fullscreen modeExit fullscreen mode

Initialization

In this section, I'll show the basic initialization ofMfArray.

From Swift Array

You can initializeMfArray from Swift's array. TheMfType will be inferred properly.

leta=MfArray([[[-8,-7,-6,-5],[-4,-3,-2,-1]],[[0,1,2,3],[4,5,6,7]]])print(a)/*mfarray = [[[ -8,     -7,     -6,     -5],[   -4,     -3,     -2,     -1]],[[  0,      1,      2,      3],[   4,      5,      6,      7]]], type=Int, shape=[2, 2, 4]*/
Enter fullscreen modeExit fullscreen mode

Arrange

You can create the sequence array.

leta=Matft.arange(start:-8,to:8,by:1,shape:[2,2,4])print(a)/*mfarray = [[[ -8,     -7,     -6,     -5],[   -4,     -3,     -2,     -1]],[[  0,      1,      2,      3],[   4,      5,      6,      7]]], type=Int, shape=[2, 2, 4]*/
Enter fullscreen modeExit fullscreen mode

Repeated Numbers

You can create the repeated numbers array such likenumpy.ones() * N.

leta=Matft.nums(Float(1),shape:[2,2,4])print(a)/*mfarray = [[[ 1.0,        1.0,        1.0,        1.0],[   1.0,        1.0,        1.0,        1.0]],[[  1.0,        1.0,        1.0,        1.0],[   1.0,        1.0,        1.0,        1.0]]], type=Float, shape=[2, 2, 4]*/
Enter fullscreen modeExit fullscreen mode

Etc.

The other functions are below;

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

MfData andMfStructure Conversion

MfArray consists of two main parts, which areMfData andMfStructure.
MfData stores the pointer of raw data, the current type (=MfType), and the "stored" raw type (=StoredType, onlyFloat orDouble). On the other hand,MfStructure stores theshape andstrides property, which represents the current array's structure and are same asNumpy.

So, when we exploits theMfData andMfStructure, changing the array's structure (=MfStructure) is very efficient. For example, when you have thea array initialized below;

leta=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]*/
Enter fullscreen modeExit fullscreen mode

Type conversion

You can convert the current type into many types byastype method or function.

leta=Matft.arange(start:0,to:27,by:1,shape:[3,3,3],mftype:.Int)print(a)/*mfarray = [[[ -6,     -5,     -4],[   -3,     -2,     -1],[   0,      1,      2]],[[  3,      4,      5],[   6,      7,      8],[   9,      10,     11]],[[  12,     13,     14],[   15,     16,     17],[   18,     19,     20]]], type=Int, shape=[3, 3, 3]*/print(a.astype(.UInt8))/*mfarray = [[[ 250,        251,        252],[   253,        254,        255],[   0,      1,      2]],[[  3,      4,      5],[   6,      7,      8],[   9,      10,     11]],[[  12,     13,     14],[   15,     16,     17],[   18,     19,     20]]], type=UInt8, shape=[3, 3, 3]*/print(a.astype(.Float))/*mfarray = [[[ -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,        8.0],[   9.0,        10.0,       11.0]],[[  12.0,       13.0,       14.0],[   15.0,       16.0,       17.0],[   18.0,       19.0,       20.0]]], type=Float, shape=[3, 3, 3]*/
Enter fullscreen modeExit fullscreen mode

Positive and Negative Indexing

You can extract the slicedMfArrray by~< efficiently.

Note that usea[0~<] instead ofa[:] to get all elements along axis (ora[Matft.all]).

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]*/print(a[Matft.all,0])//same as a[:, 0] for numpy/*mfarray = [[    0,      1,      2],  [ 9,      10,     11],  [18,      19,     20]], type=Int, shape=[3, 3]*/
Enter fullscreen modeExit fullscreen mode
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[Matft.reverse])//print(a[~<~<-1]) //alias//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]*/
Enter fullscreen modeExit fullscreen mode

Of course, you can set the value into the sliced array.

a[~<1]=Matft.arange(start:0,to:81,by:9,shape:[3,3])print(a)/*mfarray = [[[ 0,      9,      18],[   27,     36,     45],[   54,     63,     72]],[[  9,      10,     11],[   12,     13,     14],[   15,     16,     17]],[[  18,     19,     20],[   21,     22,     23],[   24,     25,     26]]], type=Int, shape=[3, 3, 3]*/
Enter fullscreen modeExit fullscreen mode

Boolean Indexing

Matft supports also boolean indexing! So, you can extract the array with a specific condition you want like this. This feature will be convenient for an image processing. See thenumpy docs for more details.

letimg=Matft.arange(start:-5,to:70,by:1,shape:[5,5,3],mftype:.Float)print(img)/*mfarray = [[[ -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,        8.0,        9.0]],[[  10.0,       11.0,       12.0],[   13.0,       14.0,       15.0],[   16.0,       17.0,       18.0],[   19.0,       20.0,       21.0],[   22.0,       23.0,       24.0]],[[  25.0,       26.0,       27.0],[   28.0,       29.0,       30.0],[   31.0,       32.0,       33.0],[   34.0,       35.0,       36.0],[   37.0,       38.0,       39.0]],[[  40.0,       41.0,       42.0],[   43.0,       44.0,       45.0],[   46.0,       47.0,       48.0],[   49.0,       50.0,       51.0],[   52.0,       53.0,       54.0]],[[  55.0,       56.0,       57.0],[   58.0,       59.0,       60.0],[   61.0,       62.0,       63.0],[   64.0,       65.0,       66.0],[   67.0,       68.0,       69.0]]], type=Float, shape=[5, 5, 3]*/print(img[img<0])/*mfarray = [   -5.0,       -4.0,       -3.0,       -2.0,       -1.0], type=Float, shape=[5]*/img[img<0]=MfArray([0])print(img)/*mfarray = [[[ 0.0,        0.0,        0.0],[   0.0,        0.0,        0.0],[   1.0,        2.0,        3.0],[   4.0,        5.0,        6.0],[   7.0,        8.0,        9.0]],[[  10.0,       11.0,       12.0],[   13.0,       14.0,       15.0],[   16.0,       17.0,       18.0],[   19.0,       20.0,       21.0],[   22.0,       23.0,       24.0]],[[  25.0,       26.0,       27.0],[   28.0,       29.0,       30.0],[   31.0,       32.0,       33.0],[   34.0,       35.0,       36.0],[   37.0,       38.0,       39.0]],[[  40.0,       41.0,       42.0],[   43.0,       44.0,       45.0],[   46.0,       47.0,       48.0],[   49.0,       50.0,       51.0],[   52.0,       53.0,       54.0]],[[  55.0,       56.0,       57.0],[   58.0,       59.0,       60.0],[   61.0,       62.0,       63.0],[   64.0,       65.0,       66.0],[   67.0,       68.0,       69.0]]], type=Float, shape=[5, 5, 3]
Enter fullscreen modeExit fullscreen mode

Fancy Indexing

Furthermore,Matft supports Fancy Indexing too! See thenumpy docs for more details.

leta=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]*/
Enter fullscreen modeExit fullscreen mode

Synchronizing extractedMfArray

As you can see the above examples,MfArray hasbase property (is similar to view in Numpy). Therefore, aMfArray extracted (Sliced) bypositive and negative indexing is synchronized. Seenumpy doc for more details.

Note that aMfArray extracted byBoolean Indexing andFancy Indexing isCOPY ofMfArray of the original one.

leta=Matft.arange(start:0,to:4*4*2,by:1,shape:[4,4,2])letb=a[0~<,1]b[~<<-1]=MfArray([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]*/
Enter fullscreen modeExit fullscreen mode

Etc.

The other conversion functions are below;

MatftNumpy
*#Matft.astype*numpy.astype
*#Matft.transpose*numpy.transpose
*#Matft.expand_dims*numpy.expand_dims
*#Matft.squeeze*numpy.squeeze
*#Matft.broadcast_to*numpy.broadcast_to
*#Matft.to_contiguous*numpy.ascontiguousarray
*#Matft.flatten*numpy.flatten
*#Matft.flip*numpy.flip
*#Matft.clip*numpy.clip
*#Matft.swapaxes*numpy.swapaxes
*#Matft.moveaxis*numpy.moveaxis
*Matft.rollnumpy.roll
*Matft.sort*numpy.sort
*Matft.argsort*numpy.argsort
^MfArray.toArray^numpy.ndarray.tolist
^MfArray.toFlattenArrayn/a
*Matft.orderedUniquenumpy.unique

Math operation

Basic mathematic operations are supported inMatft.

Arithmetic operation

print(a+a)/*mfarray = [[  0,      2,      4],[   6,      8,      10],[   12,     14,     16]], type=Int, shape=[3, 3]*/print(a-a)/*mfarray = [[  0,      0,      0],[   0,      0,      0],[   0,      0,      0]], type=Int, shape=[3, 3]*/print(a*a)/*mfarray = [[  0,      1,      4],[   9,      16,     25],[   36,     49,     64]], type=Int, shape=[3, 3]*/print(a/a)/*mfarray = [[  -nan,       0.99999994,     0.99999994],[   0.99999994,     0.99999994,     0.99999994],[   0.99999994,     0.99999994,     0.99999994]], type=Float, shape=[3, 3]*/
Enter fullscreen modeExit fullscreen mode

Broadcasting

The one of the main features inNumpy is broadcasting operation. Seenumpy doc for more details.

leta=Matft.arange(start:0,to:3*3,by:1,shape:[3,3])letb=MfArray([-4,10,2]).reshape([3,1])print(a+b)/*mfarray = [[  -4,     -3,     -2],[   13,     14,     15],[   8,      9,      10]], type=Int, shape=[3, 3]*/
Enter fullscreen modeExit fullscreen mode

Etc.

Matft has many mathematic functions.

  • Math function
MatftNumpy
#Matft.math.sinnumpy.sin
Matft.math.asinnumpy.asin
Matft.math.sinhnumpy.sinh
Matft.math.asinhnumpy.asinh
#Matft.math.cosnumpy.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.arctan2numpy.arctan2
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

Advanced operation

Matft has complex and image processing functions too!!!!
So,Matft will be very useful for the signal and image processing!
But these functions are beta versions currently (on 22/08/08).

Complex operation

You can operate the complex values like the real ones.

letreal=Matft.arange(start:0,to:16,by:1).reshape([2,2,4])letimag=Matft.arange(start:0,to:-16,by:-1).reshape([2,2,4])leta=MfArray(real:real,imag:imag)print(a)/*mfarray = [[[    0 +0j,        1 -1j,        2 -2j,        3 -3j],[    4 -4j,        5 -5j,        6 -6j,        7 -7j]],[[    8 -8j,        9 -9j,        10 -10j,        11 -11j],[    12 -12j,        13 -13j,        14 -14j,        15 -15j]]], type=Int, shape=[2, 2, 4]*/print(a+a)/*mfarray = [[[    0 +0j,        2 -2j,        4 -4j,        6 -6j],[    8 -8j,        10 -10j,        12 -12j,        14 -14j]],[[    16 -16j,        18 -18j,        20 -20j,        22 -22j],[    24 -24j,        26 -26j,        28 -28j,        30 -30j]]], type=Int, shape=[2, 2, 4]*/print(Matft.complex.angle(a))/*mfarray = [[[    -0.0,        -0.7853982,        -0.7853982,        -0.7853982],[    -0.7853982,        -0.7853982,        -0.7853982,        -0.7853982]],[[    -0.7853982,        -0.7853982,        -0.7853982,        -0.7853982],[    -0.7853982,        -0.7853982,        -0.7853982,        -0.7853982]]], type=Float, shape=[2, 2, 4]*/print(Matft.complex.conjugate(a))/*mfarray = [[[    0 +0j,        1 +1j,        2 +2j,        3 +3j],[    4 +4j,        5 +5j,        6 +6j,        7 +7j]],[[    8 +8j,        9 +9j,        10 +10j,        11 +11j],[    12 +12j,        13 +13j,        14 +14j,        15 +15j]]], type=Int, shape=[2, 2, 4]*/
Enter fullscreen modeExit fullscreen mode
MatftNumpy
Matft.complex.anglenumpy.angle
Matft.complex.conjugatenumpy.conj / numpy.conjugate
Matft.complex.absnumpy.abs / numpy.absolute

Image operation

Conversion from/toCGImage

The conversion functions betweenMfArray andCGImage are ready. So, you can implement the complex image operation code
very easily! For example, if you use theMatft's indexing feature,...

importUIKitimportMatftimportAccelerateimportCoreGraphicsimportCoreGraphics.CGBitmapContextclassViewController:UIViewController{@IBOutletweakvaroriginalImageView:UIImageView!@IBOutletweakvarreverseImageView:UIImageView!@IBOutletweakvargrayreverseImageView:UIImageView!@IBOutletweakvarswapImageView:UIImageView!overridefuncviewDidLoad(){super.viewDidLoad()self.originalImageView.image=UIImage(named:"rena.jpeg")self.reverseImageView.image=UIImage(named:"rena.jpeg")self.grayreverseImageView.image=self.convertToGrayScale(image:UIImage(named:"rena.jpeg")!)self.swapImageView.image=UIImage(named:"rena.jpeg")self.reverse()self.grayreverse()self.swapchannel()self.resize()}funcreverse(){varimage=Matft.image.cgimage2mfarray(self.reverseImageView.image!.cgImage!)// reverseimage=image[Matft.reverse]// same as image[~<<-1]self.reverseImageView.image=UIImage(cgImage:Matft.image.mfarray2cgimage(image))}funcswapchannel(){varimage=Matft.image.cgimage2mfarray(self.swapImageView.image!.cgImage!)// swap channelimage=image[Matft.all,Matft.all,MfArray([1,0,2,3])]// same as image[0~<, 0~<, MfArray([1,0,2,3])]self.swapImageView.image=UIImage(cgImage:Matft.image.mfarray2cgimage(image))}funcgrayreverse(){varimage=Matft.image.cgimage2mfarray(self.grayreverseImageView.image!.cgImage!,mftype:.UInt8)// reverseimage=image[Matft.reverse]// same as image[~<<-1]self.grayreverseImageView.image=UIImage(cgImage:Matft.image.mfarray2cgimage(image))}funcconvertToGrayScale(image:UIImage)->UIImage{//let gray_mfarray = (Matft.image.color(Matft.image.cgimage2mfarray(image.cgImage!)) * Float(255)).astype(.UInt8)letgray_mfarray=Matft.image.color(Matft.image.cgimage2mfarray(image.cgImage!))returnUIImage(cgImage:Matft.image.mfarray2cgimage(gray_mfarray))}funcresize(){varimage=Matft.image.cgimage2mfarray(self.swapImageView.image!.cgImage!)// resizeimage=Matft.image.resize(image,width:300,height:300)self.swapImageView.image=UIImage(cgImage:Matft.image.mfarray2cgimage(image))//self.swapImageView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)}}
Enter fullscreen modeExit fullscreen mode

Screen Shot 2022-07-19 at 21 09 02

Awesome!

Affine

// CGImage to MfArrayletrgb=Matft.image.cgimage2mfarray(uiimage.cgImage!)// Convert RGBA into Gray Imageletgray=Matft.image.color(rgb)// Resizeletrgb_resize=Matft.image.resize(rgb,width:150,height:150)letgray_resize=Matft.image.resize(gray,width:300,height:300)letrbg_rotated=Matft.image.warpAffine(rgb_resize,matrix:MfArray([[0,1,1],[1,0,0]]as[[Float]]),width:150,height:150)letgray_rotated=Matft.image.warpAffine(gray_resize,matrix:MfArray([[0,1,1],[1,0,0]]as[[Float]]),width:150,height:150)Matft.image.mfarray2cgimage(rbg_rotated)
Enter fullscreen modeExit fullscreen mode

Image description

MatftNumpy
Matft.image.cgimage2mfarrayN/A
Matft.image.mfarray2cgimageN/A
MatftOpenCV
Matft.image.colorcv2.cvtColor
Matft.image.resizecv2.resize
Matft.image.warpAffinecv2.warpAffine

Conclusion

I introduced theMatft in this post.Matft has many features from the basic mathematic array operations to the complicated operations such like boolean indexing, fancy indexing, complex data, image data and so on.
I hopeMatft will be useful for your project and help your project more efficient!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp