├── .gitignore ├── .travis.yml ├── AppledocSettings.plist ├── LICENSE ├── README.md ├── YCMatrix.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── yanconst.xcuserdatad │ │ └── WorkspaceSettings.xcsettings ├── xcshareddata │ └── xcschemes │ │ └── YCMatrix.xcscheme └── xcuserdata │ ├── oo.xcuserdatad │ └── xcschemes │ │ ├── YCMatrix.xcscheme │ │ └── xcschememanagement.plist │ └── yanconst.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── YCMatrix ├── Constants.h ├── HaltonInterface.h ├── HaltonInterface.mm ├── Matrix+Advanced.h ├── Matrix+Advanced.m ├── Matrix+Manipulate.h ├── Matrix+Manipulate.m ├── Matrix+Map.h ├── Matrix+Map.m ├── Matrix.h ├── Matrix.m ├── NSArray+Matrix.h ├── NSArray+Matrix.m ├── YCMatrix-Info.plist ├── YCMatrix.h ├── en.lproj │ └── InfoPlist.strings ├── halton_sampler.h └── soboldata.h ├── YCMatrixTests ├── YCMatrixAdvancedTests.m ├── YCMatrixManipulateTests.m ├── YCMatrixMapTests.m ├── YCMatrixNSArrayTests.m ├── YCMatrixPerformanceTests.m ├── YCMatrixTests-Info.plist ├── YCMatrixTests.m └── en.lproj │ └── InfoPlist.strings └── ycmatrix.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | 4 | ## Build generated 5 | build/ 6 | DerivedData/ 7 | 8 | ## Various settings 9 | *.pbxuser 10 | !default.pbxuser 11 | *.mode1v3 12 | !default.mode1v3 13 | *.mode2v3 14 | !default.mode2v3 15 | *.perspectivev3 16 | !default.perspectivev3 17 | xcuserdata/ 18 | 19 | ## Other 20 | *.moved-aside 21 | *.xccheckout 22 | *.xcscmblueprint 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | xcode_project: YCMatrix.xcodeproj 3 | osx_image: xcode7 4 | xcode_scheme: YCMatrix 5 | 6 | branches: 7 | only: 8 | - master 9 | -------------------------------------------------------------------------------- /AppledocSettings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | --project-name 6 | YCMatrix 7 | --project-version 8 | 0.6.16 9 | --project-company 10 | Ioannis Chatzikonstantinou / yconst.com 11 | --create-html 12 | 13 | --create-docset 14 | 15 | --output 16 | ./YCMatrix 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YCMatrix 2 | 3 | Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 4 | http://yconst.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | YCMatrix 3 | 4 | # YCMatrix 5 | 6 | [![Build Status](https://travis-ci.org/yconst/YCMatrix.svg?branch=master)](https://travis-ci.org/yconst/YCMatrix) 7 | [![DOI](https://zenodo.org/badge/20003/yconst/YCMatrix.svg)](https://zenodo.org/badge/latestdoi/20003/yconst/YCMatrix) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | 10 | A flexible Matrix library for Objective-C and Swift, that interfaces 11 | BLAS, LAPACK and vDSP functions via the Accelerate Framework. 12 | 13 | YCMatrix is available for MacOS (10.7+), as well as iOS (8.0+). 14 | 15 | ## Getting started 16 | 17 | ### Adding the framework to your project 18 | 19 | Import the project in your workspace, or open the framework project in XCode, build and import the product. 20 | 21 | .. or alternatively, just drag+drop the files (.h and .m) that you want to your project, presto. 22 | 23 | ### Importing 24 | 25 | YCMatrix defines a module so in newer versions of XCode, 26 | you can simply import the framework with: 27 | 28 | @include YCMatrix; 29 | 30 | Alternatively, you can do: 31 | 32 | #import "YCMatrix/YCMatrix.h" 33 | 34 | ### Dependencies 35 | 36 | YCMatrix has no dependencies other than system 37 | frameworks (namely Foundation.framework and Accelerate.framework). 38 | 39 | ### Importing/Using with CocoaPods (no longer supported) 40 | 41 | Unfortunately Cocoapods is no longer supported as of 0.6.8. The decision to end Cocoapods support is related to the increasing time needed for debugging related to Cocoapods support (e.g. Xcode/OS updates, addition of C++ etc.). Dropping Cocoapods support will allow for more time spent to developing the project. We recommend Carthage for managing your project's dependencies. You may easily include YCMatrix in your cartfile as follows: 42 | 43 | github "yconst/YCMatrix" 44 | 45 | In addition, YCMatrix can be easily included manually into an Xcode project, by copying header and implementation files (and optionally creating a new target). 46 | 47 | ## Usage 48 | 49 | ### Naming Conventions 50 | 51 | Methods that result in a new Matrix instance are usually prefixed with "matrixFrom", 52 | e.g. -matrixFromSubtraction: . Methods that change the receiver in-place 53 | do not have the prefix. In some cases, such as matrix-matrix multiplication, 54 | the prefix is not included in the method name, even though it is obvious that 55 | the result of the operation is a new Matrix instance. 56 | 57 | ### Example 58 | 59 | The snippet below is a basic example of matrix multiplication. 60 | It also shows how you can easily create matrices with predefined 61 | values. 62 | 63 | @include YCMatrix; 64 | 65 | Matrix *I = [Matrix identityOfRows:3 columns:3]; // 3x3 Identity 66 | Matrix *C = [Matrix matrixOfRows:3 columns:3 value:2]; // 3x3 filled with 2s 67 | Matrix *S = [I matrixByAddition:C]; // Outputs a new matrix 68 | NSLog(@"Result:\n%@", S); 69 | 70 | // Result: 71 | // 3.0 2.0 2.0 72 | // 2.0 3.0 2.0 73 | // 2.0 2.0 3.0 74 | 75 | ## What's in there? 76 | 77 | The Framework functionality is split into four files: The base class 78 | definition, and three categories: 79 | 80 | - Matrix.h : YCMatrix class definition and basic operations. 81 | - Matrix+Advanced.h : Interface to more advanced LAPACK functions. 82 | - Matrix+Manipulate.h : Functions for manipulating rows/columns etc. 83 | - Matrix+Map.h : Functions for linearly mapping matrices. 84 | 85 | In addition, there is a file that implements functionality related to NSArrays containing Matrices. 86 | 87 | Please refer to the [docs](http://cocoadocs.org/docsets/YCMatrix/) for a complete overview of the functionality 88 | contained in each of the categories. 89 | 90 | In addition, YCMatrix comes with many unit tests included. Tests are divided in six files: 91 | 92 | - YCMatrixTests : General Matrix-related tests. 93 | - YCMatrixAdvancedTests : Tests related to higher-level operations (decompositions, inverses etc.). 94 | - YCMatrixManipulateTests : Tests related to matrix manipulation operations. 95 | - YCMatrixMapTests : Tests related to linear mapping operations. 96 | - YCMatrixNSArrayTests : Tests related to NSArray categories. 97 | - YCMatrixPerformanceTests: Tests for measuring performance of various operations. 98 | 99 | ## Performance 100 | 101 | YCMatrix has been built from the ground up with performance in mind. vDSP, BLAS and LAPACK are being used extensively throughout the framework. In addition, care has been given in memory allocation during initialization and copying. 102 | 103 | The test file YCMatrixPerformanceTests.m contains some benchmarks using different addition/subtraction implementations (vDSP, BLAS, and pure C). 104 | 105 | ## License 106 | 107 | __YCMatrix__ 108 | 109 | Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 110 | http://yconst.com 111 | 112 | Permission is hereby granted, free of charge, to any person obtaining a copy 113 | of this software and associated documentation files (the "Software"), to deal 114 | in the Software without restriction, including without limitation the rights 115 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 116 | copies of the Software, and to permit persons to whom the Software is 117 | furnished to do so, subject to the following conditions: 118 | 119 | The above copyright notice and this permission notice shall be included in 120 | all copies or substantial portions of the Software. 121 | 122 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 123 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 124 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 125 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 126 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 127 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 128 | THE SOFTWARE. 129 | 130 | ## Acknowledgments 131 | 132 | This software relies on the following copyrighted material, the use of which is hereby acknowledged. 133 | 134 | ---- 135 | 136 | soboldata.h and sobolseq.c 137 | Part of the NLOpt Software 138 | 139 | Copyright (c) 2007 Massachusetts Institute of Technology 140 | 141 | Permission is hereby granted, free of charge, to any person obtaining 142 | a copy of this software and associated documentation files (the 143 | "Software"), to deal in the Software without restriction, including 144 | without limitation the rights to use, copy, modify, merge, publish, 145 | distribute, sublicense, and/or sell copies of the Software, and to 146 | permit persons to whom the Software is furnished to do so, subject to 147 | the following conditions: 148 | 149 | The above copyright notice and this permission notice shall be 150 | included in all copies or substantial portions of the Software. 151 | 152 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 153 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 154 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 155 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 156 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 157 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 158 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 159 | 160 | ---- 161 | 162 | haltondata.cpp 163 | 164 | Copyright (c) 2012 Leonhard Gruenschloss (leonhard@gruenschloss.org) 165 | 166 | Permission is hereby granted, free of charge, to any person obtaining a copy 167 | of this software and associated documentation files (the "Software"), to deal 168 | in the Software without restriction, including without limitation the rights to 169 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 170 | of the Software, and to permit persons to whom the Software is furnished to do 171 | so, subject to the following conditions: 172 | 173 | The above copyright notice and this permission notice shall be included in 174 | all copies or substantial portions of the Software. 175 | 176 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 177 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 179 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 180 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 181 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 182 | SOFTWARE. 183 | 184 | ---- 185 | 186 | Routine for computing the Singular Value Decomposition 187 | of *column-major* matrix A using LAPACK 188 | 189 | Author: Luke Lonergan 190 | Date: 5/31/08 191 | License: Use pfreely 192 | 193 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | CB02F7B51AAF446400EF1E02 /* YCMatrix.h in Headers */ = {isa = PBXBuildFile; fileRef = CB02F7B41AAF446400EF1E02 /* YCMatrix.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | CB0B6D391C5A5B05002A76E2 /* YCMatrixPerformanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CB0B6D381C5A5B05002A76E2 /* YCMatrixPerformanceTests.m */; }; 12 | CB26DAA21A856232007F73E2 /* NSArray+Matrix.h in Headers */ = {isa = PBXBuildFile; fileRef = CB26DAA01A856232007F73E2 /* NSArray+Matrix.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | CB26DAA31A856232007F73E2 /* NSArray+Matrix.m in Sources */ = {isa = PBXBuildFile; fileRef = CB26DAA11A856232007F73E2 /* NSArray+Matrix.m */; }; 14 | CB4388EA1C2887BE00C6D330 /* halton_sampler.h in Headers */ = {isa = PBXBuildFile; fileRef = CB4388E91C2887BE00C6D330 /* halton_sampler.h */; }; 15 | CB4D3CA81C10F092009CAE8B /* soboldata.h in Headers */ = {isa = PBXBuildFile; fileRef = CB4D3CA71C10F092009CAE8B /* soboldata.h */; }; 16 | CB723AFC1C47C37600600043 /* YCMatrixNSArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CB723AFB1C47C37600600043 /* YCMatrixNSArrayTests.m */; }; 17 | CBBE02BA178F215000744F77 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CBBE02B8178F215000744F77 /* InfoPlist.strings */; }; 18 | CBBE02BE178F215000744F77 /* Matrix.m in Sources */ = {isa = PBXBuildFile; fileRef = CBBE02BD178F215000744F77 /* Matrix.m */; }; 19 | CBBE02CA178F215100744F77 /* YCMatrix.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBBE02AC178F215000744F77 /* YCMatrix.framework */; }; 20 | CBBE02D0178F215100744F77 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CBBE02CE178F215100744F77 /* InfoPlist.strings */; }; 21 | CBBE02D3178F215100744F77 /* YCMatrixTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CBBE02D2178F215100744F77 /* YCMatrixTests.m */; }; 22 | CBBE02E0178F216800744F77 /* Matrix+Advanced.h in Headers */ = {isa = PBXBuildFile; fileRef = CBBE02DC178F216800744F77 /* Matrix+Advanced.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23 | CBBE02E1178F216800744F77 /* Matrix+Advanced.m in Sources */ = {isa = PBXBuildFile; fileRef = CBBE02DD178F216800744F77 /* Matrix+Advanced.m */; }; 24 | CBBE02E2178F216800744F77 /* Matrix+Manipulate.h in Headers */ = {isa = PBXBuildFile; fileRef = CBBE02DE178F216800744F77 /* Matrix+Manipulate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25 | CBBE02E3178F216800744F77 /* Matrix+Manipulate.m in Sources */ = {isa = PBXBuildFile; fileRef = CBBE02DF178F216800744F77 /* Matrix+Manipulate.m */; }; 26 | CBBE02E9178F218600744F77 /* YCMatrixManipulateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CBBE02E7178F218600744F77 /* YCMatrixManipulateTests.m */; }; 27 | CBBE0301178F258B00744F77 /* Matrix.h in Headers */ = {isa = PBXBuildFile; fileRef = CBBE02BC178F215000744F77 /* Matrix.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | CBCF36241C28383D009D89D7 /* HaltonInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = CBCF36221C28383D009D89D7 /* HaltonInterface.h */; }; 29 | CBCF36251C28383D009D89D7 /* HaltonInterface.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBCF36231C28383D009D89D7 /* HaltonInterface.mm */; }; 30 | CBD5120719D37764004DD8D3 /* Constants.h in Headers */ = {isa = PBXBuildFile; fileRef = CBD5120619D37764004DD8D3 /* Constants.h */; }; 31 | CBD7D3D218A4DD10006A04C0 /* Matrix+Map.h in Headers */ = {isa = PBXBuildFile; fileRef = CBD7D3D018A4DD10006A04C0 /* Matrix+Map.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32 | CBD7D3D318A4DD10006A04C0 /* Matrix+Map.m in Sources */ = {isa = PBXBuildFile; fileRef = CBD7D3D118A4DD10006A04C0 /* Matrix+Map.m */; }; 33 | CBE66B9A1A6BB0A000E2EF2C /* YCMatrixMapTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE66B991A6BB0A000E2EF2C /* YCMatrixMapTests.m */; }; 34 | CBE9E7AD19D0D79600460953 /* YCMatrixAdvancedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE9E7AC19D0D79600460953 /* YCMatrixAdvancedTests.m */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXContainerItemProxy section */ 38 | CBBE02C8178F215100744F77 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = CBBE02A3178F215000744F77 /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = CBBE02AB178F215000744F77; 43 | remoteInfo = YCMatrix; 44 | }; 45 | /* End PBXContainerItemProxy section */ 46 | 47 | /* Begin PBXFileReference section */ 48 | CB02F7B41AAF446400EF1E02 /* YCMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = YCMatrix.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 49 | CB0B6D381C5A5B05002A76E2 /* YCMatrixPerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YCMatrixPerformanceTests.m; sourceTree = ""; }; 50 | CB2242AF19D413C0005B3F7E /* AppledocSettings.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = AppledocSettings.plist; sourceTree = ""; }; 51 | CB265CCD1B24BB55004BE740 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; }; 52 | CB26DAA01A856232007F73E2 /* NSArray+Matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "NSArray+Matrix.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 53 | CB26DAA11A856232007F73E2 /* NSArray+Matrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "NSArray+Matrix.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 54 | CB4388E91C2887BE00C6D330 /* halton_sampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = halton_sampler.h; sourceTree = ""; }; 55 | CB4BAA9919D2CE3D001E7A7A /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; 56 | CB4D3CA71C10F092009CAE8B /* soboldata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = soboldata.h; sourceTree = ""; }; 57 | CB58B99D19D1ED310097EEB1 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 58 | CB723AFB1C47C37600600043 /* YCMatrixNSArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YCMatrixNSArrayTests.m; sourceTree = ""; }; 59 | CB84DE0319D4BD32009EED7E /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; path = LICENSE; sourceTree = ""; xcLanguageSpecificationIdentifier = ""; }; 60 | CB9F9CFC19DAE83E00B6A1E4 /* ycmatrix.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ycmatrix.png; sourceTree = ""; }; 61 | CBBE02AC178F215000744F77 /* YCMatrix.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YCMatrix.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | CBBE02B4178F215000744F77 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 63 | CBBE02B7178F215000744F77 /* YCMatrix-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "YCMatrix-Info.plist"; sourceTree = ""; }; 64 | CBBE02B9178F215000744F77 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 65 | CBBE02BC178F215000744F77 /* Matrix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Matrix.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 66 | CBBE02BD178F215000744F77 /* Matrix.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Matrix.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 67 | CBBE02C4178F215100744F77 /* YCMatrixTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YCMatrixTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | CBBE02CD178F215100744F77 /* YCMatrixTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "YCMatrixTests-Info.plist"; sourceTree = ""; }; 69 | CBBE02CF178F215100744F77 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 70 | CBBE02D2178F215100744F77 /* YCMatrixTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YCMatrixTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 71 | CBBE02DC178F216800744F77 /* Matrix+Advanced.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "Matrix+Advanced.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 72 | CBBE02DD178F216800744F77 /* Matrix+Advanced.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "Matrix+Advanced.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 73 | CBBE02DE178F216800744F77 /* Matrix+Manipulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "Matrix+Manipulate.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 74 | CBBE02DF178F216800744F77 /* Matrix+Manipulate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "Matrix+Manipulate.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 75 | CBBE02E7178F218600744F77 /* YCMatrixManipulateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YCMatrixManipulateTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 76 | CBCF36221C28383D009D89D7 /* HaltonInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HaltonInterface.h; sourceTree = ""; }; 77 | CBCF36231C28383D009D89D7 /* HaltonInterface.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HaltonInterface.mm; sourceTree = ""; }; 78 | CBD5120519D2D720004DD8D3 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = ""; }; 79 | CBD5120619D37764004DD8D3 /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; 80 | CBD7D3D018A4DD10006A04C0 /* Matrix+Map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "Matrix+Map.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 81 | CBD7D3D118A4DD10006A04C0 /* Matrix+Map.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "Matrix+Map.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 82 | CBE66B991A6BB0A000E2EF2C /* YCMatrixMapTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YCMatrixMapTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 83 | CBE9E7AC19D0D79600460953 /* YCMatrixAdvancedTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = YCMatrixAdvancedTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | CBBE02A8178F215000744F77 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | CBBE02C0178F215100744F77 /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | CBBE02CA178F215100744F77 /* YCMatrix.framework in Frameworks */, 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | /* End PBXFrameworksBuildPhase section */ 103 | 104 | /* Begin PBXGroup section */ 105 | CB26DA9F1A856219007F73E2 /* Categories */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | CB26DAA01A856232007F73E2 /* NSArray+Matrix.h */, 109 | CB26DAA11A856232007F73E2 /* NSArray+Matrix.m */, 110 | ); 111 | name = Categories; 112 | sourceTree = ""; 113 | }; 114 | CBBE02A2178F215000744F77 = { 115 | isa = PBXGroup; 116 | children = ( 117 | CBBE02B5178F215000744F77 /* YCMatrix */, 118 | CBBE02CB178F215100744F77 /* YCMatrixTests */, 119 | CBBE02AE178F215000744F77 /* Frameworks */, 120 | CBBE02AD178F215000744F77 /* Products */, 121 | CB58B99D19D1ED310097EEB1 /* README.md */, 122 | CB84DE0319D4BD32009EED7E /* LICENSE */, 123 | CB4BAA9919D2CE3D001E7A7A /* .gitignore */, 124 | CBD5120519D2D720004DD8D3 /* .travis.yml */, 125 | CB2242AF19D413C0005B3F7E /* AppledocSettings.plist */, 126 | CB9F9CFC19DAE83E00B6A1E4 /* ycmatrix.png */, 127 | ); 128 | sourceTree = ""; 129 | }; 130 | CBBE02AD178F215000744F77 /* Products */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | CBBE02AC178F215000744F77 /* YCMatrix.framework */, 134 | CBBE02C4178F215100744F77 /* YCMatrixTests.xctest */, 135 | ); 136 | name = Products; 137 | sourceTree = ""; 138 | }; 139 | CBBE02AE178F215000744F77 /* Frameworks */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | CB265CCD1B24BB55004BE740 /* Accelerate.framework */, 143 | CBBE02B4178F215000744F77 /* Foundation.framework */, 144 | ); 145 | name = Frameworks; 146 | sourceTree = ""; 147 | }; 148 | CBBE02B5178F215000744F77 /* YCMatrix */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | CB02F7B41AAF446400EF1E02 /* YCMatrix.h */, 152 | CBBE02BC178F215000744F77 /* Matrix.h */, 153 | CBBE02BD178F215000744F77 /* Matrix.m */, 154 | CBBE02DC178F216800744F77 /* Matrix+Advanced.h */, 155 | CBBE02DD178F216800744F77 /* Matrix+Advanced.m */, 156 | CBBE02DE178F216800744F77 /* Matrix+Manipulate.h */, 157 | CBBE02DF178F216800744F77 /* Matrix+Manipulate.m */, 158 | CBD7D3D018A4DD10006A04C0 /* Matrix+Map.h */, 159 | CBD7D3D118A4DD10006A04C0 /* Matrix+Map.m */, 160 | CB26DA9F1A856219007F73E2 /* Categories */, 161 | CBBE02B6178F215000744F77 /* Supporting Files */, 162 | ); 163 | path = YCMatrix; 164 | sourceTree = ""; 165 | }; 166 | CBBE02B6178F215000744F77 /* Supporting Files */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | CBCF36221C28383D009D89D7 /* HaltonInterface.h */, 170 | CBCF36231C28383D009D89D7 /* HaltonInterface.mm */, 171 | CB4388E91C2887BE00C6D330 /* halton_sampler.h */, 172 | CB4D3CA71C10F092009CAE8B /* soboldata.h */, 173 | CBBE02B7178F215000744F77 /* YCMatrix-Info.plist */, 174 | CBBE02B8178F215000744F77 /* InfoPlist.strings */, 175 | CBD5120619D37764004DD8D3 /* Constants.h */, 176 | ); 177 | name = "Supporting Files"; 178 | sourceTree = ""; 179 | }; 180 | CBBE02CB178F215100744F77 /* YCMatrixTests */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | CBBE02D2178F215100744F77 /* YCMatrixTests.m */, 184 | CBE9E7AC19D0D79600460953 /* YCMatrixAdvancedTests.m */, 185 | CBBE02E7178F218600744F77 /* YCMatrixManipulateTests.m */, 186 | CBE66B991A6BB0A000E2EF2C /* YCMatrixMapTests.m */, 187 | CB723AFB1C47C37600600043 /* YCMatrixNSArrayTests.m */, 188 | CB0B6D381C5A5B05002A76E2 /* YCMatrixPerformanceTests.m */, 189 | CBBE02CC178F215100744F77 /* Supporting Files */, 190 | ); 191 | path = YCMatrixTests; 192 | sourceTree = ""; 193 | }; 194 | CBBE02CC178F215100744F77 /* Supporting Files */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | CBBE02CD178F215100744F77 /* YCMatrixTests-Info.plist */, 198 | CBBE02CE178F215100744F77 /* InfoPlist.strings */, 199 | ); 200 | name = "Supporting Files"; 201 | sourceTree = ""; 202 | }; 203 | /* End PBXGroup section */ 204 | 205 | /* Begin PBXHeadersBuildPhase section */ 206 | CBBE02A9178F215000744F77 /* Headers */ = { 207 | isa = PBXHeadersBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | CBD5120719D37764004DD8D3 /* Constants.h in Headers */, 211 | CBCF36241C28383D009D89D7 /* HaltonInterface.h in Headers */, 212 | CB02F7B51AAF446400EF1E02 /* YCMatrix.h in Headers */, 213 | CB4D3CA81C10F092009CAE8B /* soboldata.h in Headers */, 214 | CBBE02E0178F216800744F77 /* Matrix+Advanced.h in Headers */, 215 | CB4388EA1C2887BE00C6D330 /* halton_sampler.h in Headers */, 216 | CB26DAA21A856232007F73E2 /* NSArray+Matrix.h in Headers */, 217 | CBBE02E2178F216800744F77 /* Matrix+Manipulate.h in Headers */, 218 | CBBE0301178F258B00744F77 /* Matrix.h in Headers */, 219 | CBD7D3D218A4DD10006A04C0 /* Matrix+Map.h in Headers */, 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | /* End PBXHeadersBuildPhase section */ 224 | 225 | /* Begin PBXNativeTarget section */ 226 | CBBE02AB178F215000744F77 /* YCMatrix */ = { 227 | isa = PBXNativeTarget; 228 | buildConfigurationList = CBBE02D6178F215100744F77 /* Build configuration list for PBXNativeTarget "YCMatrix" */; 229 | buildPhases = ( 230 | CBBE02A7178F215000744F77 /* Sources */, 231 | CBBE02A8178F215000744F77 /* Frameworks */, 232 | CBBE02A9178F215000744F77 /* Headers */, 233 | CBBE02AA178F215000744F77 /* Resources */, 234 | ); 235 | buildRules = ( 236 | ); 237 | dependencies = ( 238 | ); 239 | name = YCMatrix; 240 | productName = YCMatrix; 241 | productReference = CBBE02AC178F215000744F77 /* YCMatrix.framework */; 242 | productType = "com.apple.product-type.framework"; 243 | }; 244 | CBBE02C3178F215100744F77 /* YCMatrixTests */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = CBBE02D9178F215100744F77 /* Build configuration list for PBXNativeTarget "YCMatrixTests" */; 247 | buildPhases = ( 248 | CBBE02BF178F215100744F77 /* Sources */, 249 | CBBE02C0178F215100744F77 /* Frameworks */, 250 | CBBE02C1178F215100744F77 /* Resources */, 251 | ); 252 | buildRules = ( 253 | ); 254 | dependencies = ( 255 | CBBE02C9178F215100744F77 /* PBXTargetDependency */, 256 | ); 257 | name = YCMatrixTests; 258 | productName = YCMatrixTests; 259 | productReference = CBBE02C4178F215100744F77 /* YCMatrixTests.xctest */; 260 | productType = "com.apple.product-type.bundle.unit-test"; 261 | }; 262 | /* End PBXNativeTarget section */ 263 | 264 | /* Begin PBXProject section */ 265 | CBBE02A3178F215000744F77 /* Project object */ = { 266 | isa = PBXProject; 267 | attributes = { 268 | LastUpgradeCheck = 0800; 269 | ORGANIZATIONNAME = "Ioannis Chatzikonstantinou"; 270 | }; 271 | buildConfigurationList = CBBE02A6178F215000744F77 /* Build configuration list for PBXProject "YCMatrix" */; 272 | compatibilityVersion = "Xcode 3.2"; 273 | developmentRegion = English; 274 | hasScannedForEncodings = 0; 275 | knownRegions = ( 276 | en, 277 | ); 278 | mainGroup = CBBE02A2178F215000744F77; 279 | productRefGroup = CBBE02AD178F215000744F77 /* Products */; 280 | projectDirPath = ""; 281 | projectRoot = ""; 282 | targets = ( 283 | CBBE02AB178F215000744F77 /* YCMatrix */, 284 | CBBE02C3178F215100744F77 /* YCMatrixTests */, 285 | ); 286 | }; 287 | /* End PBXProject section */ 288 | 289 | /* Begin PBXResourcesBuildPhase section */ 290 | CBBE02AA178F215000744F77 /* Resources */ = { 291 | isa = PBXResourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | CBBE02BA178F215000744F77 /* InfoPlist.strings in Resources */, 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | CBBE02C1178F215100744F77 /* Resources */ = { 299 | isa = PBXResourcesBuildPhase; 300 | buildActionMask = 2147483647; 301 | files = ( 302 | CBBE02D0178F215100744F77 /* InfoPlist.strings in Resources */, 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | }; 306 | /* End PBXResourcesBuildPhase section */ 307 | 308 | /* Begin PBXSourcesBuildPhase section */ 309 | CBBE02A7178F215000744F77 /* Sources */ = { 310 | isa = PBXSourcesBuildPhase; 311 | buildActionMask = 2147483647; 312 | files = ( 313 | CB26DAA31A856232007F73E2 /* NSArray+Matrix.m in Sources */, 314 | CBD7D3D318A4DD10006A04C0 /* Matrix+Map.m in Sources */, 315 | CBBE02BE178F215000744F77 /* Matrix.m in Sources */, 316 | CBCF36251C28383D009D89D7 /* HaltonInterface.mm in Sources */, 317 | CBBE02E1178F216800744F77 /* Matrix+Advanced.m in Sources */, 318 | CBBE02E3178F216800744F77 /* Matrix+Manipulate.m in Sources */, 319 | ); 320 | runOnlyForDeploymentPostprocessing = 0; 321 | }; 322 | CBBE02BF178F215100744F77 /* Sources */ = { 323 | isa = PBXSourcesBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | CBE9E7AD19D0D79600460953 /* YCMatrixAdvancedTests.m in Sources */, 327 | CB0B6D391C5A5B05002A76E2 /* YCMatrixPerformanceTests.m in Sources */, 328 | CB723AFC1C47C37600600043 /* YCMatrixNSArrayTests.m in Sources */, 329 | CBBE02D3178F215100744F77 /* YCMatrixTests.m in Sources */, 330 | CBBE02E9178F218600744F77 /* YCMatrixManipulateTests.m in Sources */, 331 | CBE66B9A1A6BB0A000E2EF2C /* YCMatrixMapTests.m in Sources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | /* End PBXSourcesBuildPhase section */ 336 | 337 | /* Begin PBXTargetDependency section */ 338 | CBBE02C9178F215100744F77 /* PBXTargetDependency */ = { 339 | isa = PBXTargetDependency; 340 | target = CBBE02AB178F215000744F77 /* YCMatrix */; 341 | targetProxy = CBBE02C8178F215100744F77 /* PBXContainerItemProxy */; 342 | }; 343 | /* End PBXTargetDependency section */ 344 | 345 | /* Begin PBXVariantGroup section */ 346 | CBBE02B8178F215000744F77 /* InfoPlist.strings */ = { 347 | isa = PBXVariantGroup; 348 | children = ( 349 | CBBE02B9178F215000744F77 /* en */, 350 | ); 351 | name = InfoPlist.strings; 352 | sourceTree = ""; 353 | }; 354 | CBBE02CE178F215100744F77 /* InfoPlist.strings */ = { 355 | isa = PBXVariantGroup; 356 | children = ( 357 | CBBE02CF178F215100744F77 /* en */, 358 | ); 359 | name = InfoPlist.strings; 360 | sourceTree = ""; 361 | }; 362 | /* End PBXVariantGroup section */ 363 | 364 | /* Begin XCBuildConfiguration section */ 365 | CBBE02D4178F215100744F77 /* Debug */ = { 366 | isa = XCBuildConfiguration; 367 | buildSettings = { 368 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 369 | ALWAYS_SEARCH_USER_PATHS = NO; 370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 371 | CLANG_CXX_LIBRARY = "libc++"; 372 | CLANG_ENABLE_OBJC_ARC = YES; 373 | CLANG_WARN_BOOL_CONVERSION = YES; 374 | CLANG_WARN_CONSTANT_CONVERSION = YES; 375 | CLANG_WARN_EMPTY_BODY = YES; 376 | CLANG_WARN_ENUM_CONVERSION = YES; 377 | CLANG_WARN_INFINITE_RECURSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 380 | CLANG_WARN_UNREACHABLE_CODE = YES; 381 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 382 | COPY_PHASE_STRIP = NO; 383 | ENABLE_STRICT_OBJC_MSGSEND = YES; 384 | ENABLE_TESTABILITY = YES; 385 | GCC_C_LANGUAGE_STANDARD = gnu99; 386 | GCC_DYNAMIC_NO_PIC = NO; 387 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 388 | GCC_NO_COMMON_BLOCKS = YES; 389 | GCC_OPTIMIZATION_LEVEL = 0; 390 | GCC_PREPROCESSOR_DEFINITIONS = ( 391 | "DEBUG=1", 392 | "$(inherited)", 393 | ); 394 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | MACOSX_DEPLOYMENT_TARGET = 10.7; 402 | ONLY_ACTIVE_ARCH = YES; 403 | SDKROOT = macosx; 404 | SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; 405 | VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64"; 406 | }; 407 | name = Debug; 408 | }; 409 | CBBE02D5178F215100744F77 /* Release */ = { 410 | isa = XCBuildConfiguration; 411 | buildSettings = { 412 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 415 | CLANG_CXX_LIBRARY = "libc++"; 416 | CLANG_ENABLE_OBJC_ARC = YES; 417 | CLANG_WARN_BOOL_CONVERSION = YES; 418 | CLANG_WARN_CONSTANT_CONVERSION = YES; 419 | CLANG_WARN_EMPTY_BODY = YES; 420 | CLANG_WARN_ENUM_CONVERSION = YES; 421 | CLANG_WARN_INFINITE_RECURSION = YES; 422 | CLANG_WARN_INT_CONVERSION = YES; 423 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | COPY_PHASE_STRIP = YES; 427 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 428 | ENABLE_STRICT_OBJC_MSGSEND = YES; 429 | GCC_C_LANGUAGE_STANDARD = gnu99; 430 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 431 | GCC_NO_COMMON_BLOCKS = YES; 432 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 433 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 434 | GCC_WARN_UNDECLARED_SELECTOR = YES; 435 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 436 | GCC_WARN_UNUSED_FUNCTION = YES; 437 | GCC_WARN_UNUSED_VARIABLE = YES; 438 | MACOSX_DEPLOYMENT_TARGET = 10.7; 439 | SDKROOT = macosx; 440 | SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; 441 | VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64"; 442 | }; 443 | name = Release; 444 | }; 445 | CBBE02D7178F215100744F77 /* Debug */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | CLANG_ENABLE_MODULES = YES; 449 | COMBINE_HIDPI_IMAGES = YES; 450 | DEFINES_MODULE = YES; 451 | DYLIB_COMPATIBILITY_VERSION = 1; 452 | DYLIB_CURRENT_VERSION = 1; 453 | FRAMEWORK_SEARCH_PATHS = ""; 454 | FRAMEWORK_VERSION = A; 455 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 456 | INFOPLIST_FILE = "YCMatrix/YCMatrix-Info.plist"; 457 | INSTALL_PATH = "@rpath"; 458 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 459 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 460 | PRODUCT_BUNDLE_IDENTIFIER = "yconst.$(PRODUCT_NAME:rfc1034identifier)"; 461 | PRODUCT_NAME = "$(TARGET_NAME)"; 462 | SKIP_INSTALL = YES; 463 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 464 | VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64"; 465 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 466 | WRAPPER_EXTENSION = framework; 467 | }; 468 | name = Debug; 469 | }; 470 | CBBE02D8178F215100744F77 /* Release */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | CLANG_ENABLE_MODULES = YES; 474 | COMBINE_HIDPI_IMAGES = YES; 475 | DEFINES_MODULE = YES; 476 | DYLIB_COMPATIBILITY_VERSION = 1; 477 | DYLIB_CURRENT_VERSION = 1; 478 | FRAMEWORK_SEARCH_PATHS = ""; 479 | FRAMEWORK_VERSION = A; 480 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 481 | INFOPLIST_FILE = "YCMatrix/YCMatrix-Info.plist"; 482 | INSTALL_PATH = "@rpath"; 483 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 484 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 485 | PRODUCT_BUNDLE_IDENTIFIER = "yconst.$(PRODUCT_NAME:rfc1034identifier)"; 486 | PRODUCT_NAME = "$(TARGET_NAME)"; 487 | SKIP_INSTALL = YES; 488 | VALID_ARCHS = "arm64 armv7 armv7s i386 x86_64"; 489 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 490 | WRAPPER_EXTENSION = framework; 491 | }; 492 | name = Release; 493 | }; 494 | CBBE02DA178F215100744F77 /* Debug */ = { 495 | isa = XCBuildConfiguration; 496 | buildSettings = { 497 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; 498 | CLANG_ENABLE_MODULES = YES; 499 | CODE_SIGN_IDENTITY = ""; 500 | COMBINE_HIDPI_IMAGES = YES; 501 | FRAMEWORK_SEARCH_PATHS = ( 502 | "$(SDKROOT)", 503 | "$(inherited)", 504 | "$(DEVELOPER_FRAMEWORKS_DIR)", 505 | ); 506 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 507 | INFOPLIST_FILE = "YCMatrixTests/YCMatrixTests-Info.plist"; 508 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks"; 509 | PRODUCT_BUNDLE_IDENTIFIER = "yconst.${PRODUCT_NAME:rfc1034identifier}"; 510 | PRODUCT_NAME = "$(TARGET_NAME)"; 511 | }; 512 | name = Debug; 513 | }; 514 | CBBE02DB178F215100744F77 /* Release */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; 518 | CLANG_ENABLE_MODULES = YES; 519 | CODE_SIGN_IDENTITY = ""; 520 | COMBINE_HIDPI_IMAGES = YES; 521 | FRAMEWORK_SEARCH_PATHS = ( 522 | "$(SDKROOT)", 523 | "$(inherited)", 524 | "$(DEVELOPER_FRAMEWORKS_DIR)", 525 | ); 526 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 527 | INFOPLIST_FILE = "YCMatrixTests/YCMatrixTests-Info.plist"; 528 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks"; 529 | PRODUCT_BUNDLE_IDENTIFIER = "yconst.${PRODUCT_NAME:rfc1034identifier}"; 530 | PRODUCT_NAME = "$(TARGET_NAME)"; 531 | }; 532 | name = Release; 533 | }; 534 | /* End XCBuildConfiguration section */ 535 | 536 | /* Begin XCConfigurationList section */ 537 | CBBE02A6178F215000744F77 /* Build configuration list for PBXProject "YCMatrix" */ = { 538 | isa = XCConfigurationList; 539 | buildConfigurations = ( 540 | CBBE02D4178F215100744F77 /* Debug */, 541 | CBBE02D5178F215100744F77 /* Release */, 542 | ); 543 | defaultConfigurationIsVisible = 0; 544 | defaultConfigurationName = Release; 545 | }; 546 | CBBE02D6178F215100744F77 /* Build configuration list for PBXNativeTarget "YCMatrix" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | CBBE02D7178F215100744F77 /* Debug */, 550 | CBBE02D8178F215100744F77 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | CBBE02D9178F215100744F77 /* Build configuration list for PBXNativeTarget "YCMatrixTests" */ = { 556 | isa = XCConfigurationList; 557 | buildConfigurations = ( 558 | CBBE02DA178F215100744F77 /* Debug */, 559 | CBBE02DB178F215100744F77 /* Release */, 560 | ); 561 | defaultConfigurationIsVisible = 0; 562 | defaultConfigurationName = Release; 563 | }; 564 | /* End XCConfigurationList section */ 565 | }; 566 | rootObject = CBBE02A3178F215000744F77 /* Project object */; 567 | } 568 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/project.xcworkspace/xcuserdata/yanconst.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/xcshareddata/xcschemes/YCMatrix.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 74 | 75 | 81 | 82 | 84 | 85 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/xcuserdata/oo.xcuserdatad/xcschemes/YCMatrix.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 52 | 53 | 54 | 55 | 61 | 62 | 64 | 65 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/xcuserdata/oo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | YCMatrix.xcscheme 8 | 9 | orderHint 10 | 4 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | CBBE02AB178F215000744F77 16 | 17 | primary 18 | 19 | 20 | CBBE02C3178F215100744F77 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/xcuserdata/yanconst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /YCMatrix.xcodeproj/xcuserdata/yanconst.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | YCMatrix.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | CB265CB31B24BB30004BE740 16 | 17 | primary 18 | 19 | 20 | CB265CBD1B24BB30004BE740 21 | 22 | primary 23 | 24 | 25 | CB265CE01B24BD24004BE740 26 | 27 | primary 28 | 29 | 30 | CB265CEA1B24BD24004BE740 31 | 32 | primary 33 | 34 | 35 | CB265D0E1B24C309004BE740 36 | 37 | primary 38 | 39 | 40 | CB265D281B24C478004BE740 41 | 42 | primary 43 | 44 | 45 | CBBE02AB178F215000744F77 46 | 47 | primary 48 | 49 | 50 | CBBE02C3178F215100744F77 51 | 52 | primary 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /YCMatrix/Constants.h: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.h 3 | // YCMatrix 4 | // 5 | // Created by Ioannis Chatzikonstantinou on 25/9/14. 6 | // Copyright (c) 2014 Ioannis Chatzikonstantinou. All rights reserved. 7 | // 8 | 9 | #ifndef YCMatrix_Constants_h 10 | #define YCMatrix_Constants_h 11 | 12 | #define ARC4RANDOM_MAX 0x100000000 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /YCMatrix/HaltonInterface.h: -------------------------------------------------------------------------------- 1 | // 2 | // HaltonInterface.h 3 | // YCMatrix 4 | // 5 | // Created by Ioannis Chatzikonstantinou on 21/12/15. 6 | // Copyright © 2015 Ioannis Chatzikonstantinou. All rights reserved. 7 | // 8 | 9 | #import 10 | @class Matrix; 11 | 12 | @interface HaltonInterface : NSObject 13 | 14 | + (Matrix *)sampleWithDimension:(int)dimension count:(int)count; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /YCMatrix/HaltonInterface.mm: -------------------------------------------------------------------------------- 1 | // 2 | // HaltonInterface.m 3 | // YCMatrix 4 | // 5 | // Created by Ioannis Chatzikonstantinou on 21/12/15. 6 | // Copyright © 2015 Ioannis Chatzikonstantinou. All rights reserved. 7 | // 8 | 9 | #import "HaltonInterface.h" 10 | #import "Matrix.h" 11 | #import "halton_sampler.h" 12 | 13 | @implementation HaltonInterface 14 | 15 | + (Matrix *)sampleWithDimension:(int)dimension count:(int)count 16 | { 17 | Halton_sampler halton_sampler; 18 | halton_sampler.init_faure(); 19 | 20 | Matrix *result = [Matrix matrixOfRows:dimension columns:count]; 21 | 22 | for (unsigned i = 0; i < dimension; ++i) // Iterate over rows. 23 | { 24 | for (unsigned j = 0; j < count; ++j) // Iterate over columns. 25 | { 26 | [result i:i j:j set:halton_sampler.sample(i, j)]; 27 | } 28 | } 29 | return result; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /YCMatrix/Matrix+Advanced.h: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix+Advanced.h 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import "Matrix.h" 29 | #import "Matrix+Manipulate.h" 30 | #import "Matrix+Map.h" 31 | #import 32 | 33 | /** 34 | Advanced is a category to the Matrix class, that exposes some 35 | more complex behavior. 36 | */ 37 | @interface Matrix (Advanced) 38 | 39 | /** 40 | Returns a matrix containing random values uniformly distributed between |lower| and |upper|. 41 | The parameter matrices should have the same dimensions, and the resulting 42 | matrix will also be of the same dimensions as the parameters. 43 | 44 | @param lower Matrix containing values for the lower bounds. 45 | @param upper Matrix containing values for the upper bounds. 46 | 47 | @return A matrix of random values between lower and upper, and of the same size. 48 | */ 49 | + (instancetype)uniformRandomLowerBound:(Matrix *)lower upperBound:(Matrix *)upper; 50 | 51 | /** 52 | Returns a matrix of random values uniformly distributed within the specified domain. 53 | 54 | @param rows The number of rows of the matrix. 55 | @param columns The number of columns of the matrix. 56 | @param domain The domain to generate uniform random number within. 57 | 58 | @return A matrix of random values. 59 | */ 60 | + (instancetype)uniformRandomRows:(int)rows columns:(int)columns domain:(YCDomain)domain; 61 | 62 | /** 63 | Returns a matrix containing random values uniformly distributed between |lower| and |upper|. 64 | The lower and upper matrices should be either row or column matrices. The method will 65 | generate |count| random row or column matrices, and return them in a single matrix. 66 | As an example, if the sizes of |lower| and |upper| are mx1 and the value of the count parameter 67 | is n, the return matrix will be mxn. Conversely, if |lower| and |upper| are 1xm and count is 68 | n, the return matrix will be nxm. 69 | 70 | @param lower The matrix containing the lower bounds for the uniform random numbers. 71 | @param upper The matrix containing the upper bounds for the uniform random numbers. 72 | @param count The number of examples to generate. 73 | 74 | @return The matrix containing the uniform random numbers. 75 | 76 | @warning The lower and upper matrices should be either row or column matrices. 77 | */ 78 | + (instancetype)uniformRandomLowerBound:(Matrix *)lower 79 | upperBound:(Matrix *)upper 80 | count:(int)count; 81 | 82 | /** 83 | Returns a matrix containing random values normally distributed 84 | with specified mean and variance. The parameter matrices should have 85 | the same dimensions, and the resulting matrix will also be of the same 86 | dimensions as the parameters. 87 | 88 | @param mean Matrix containing values for the means. 89 | @param variance Matrix containing values for the variances. 90 | 91 | @return A matrix of random values between lower and upper, and of the same size. 92 | */ 93 | + (instancetype)normalRandomMean:(Matrix *)mean variance:(Matrix *)variance; 94 | 95 | /** 96 | Returns a matrix of random values uniformly distributed with specified mean and variance. 97 | 98 | @param rows The number of rows of the matrix. 99 | @param columns The number of columns of the matrix. 100 | @param mean The mean of the normal distribution. 101 | @param variance The variance of the normal distribution. 102 | 103 | @return A matrix of random values. 104 | */ 105 | + (instancetype)normalRandomRows:(int)rows 106 | columns:(int)columns 107 | mean:(double)mean 108 | variance:(double)variance; 109 | 110 | /** 111 | Returns a matrix containing random values normally distributed with specified mean and variance. 112 | The mean and variance matrices should be either row or column matrices. The method will 113 | generate |count| random row or column matrices, and return them in a single matrix. 114 | As an example, if the sizes of |mean| and |variance| are mx1 and the value of the count parameter 115 | is n, the return matrix will be mxn. Conversely, if |mean| and |variance| are 1xm and count is 116 | n, the return matrix will be nxm. 117 | 118 | @param mean The matrix containing the means of the normally distributed random numbers. 119 | @param variance The matrix containing the variances of the normally distributed random numbers. 120 | @param count The number of examples to generate. 121 | 122 | @return The matrix containing the normally distributed random numbers. 123 | 124 | @warning The mean and variance matrices should be either row or column matrices. 125 | */ 126 | + (instancetype)normalRandomMean:(Matrix *)mean 127 | variance:(Matrix *)variance 128 | count:(int)count; 129 | 130 | /** 131 | Returns a matrix of quasi-random values according to the Sobol sequence. 132 | The parameter matrices should have the same dimensions, and the resulting 133 | matrix will also be of the same dimensions as the parameters. 134 | 135 | @param lower Matrix containing values for the lower bounds. 136 | @param upper Matrix containing values for the upper bounds. 137 | @param count The number of points to sample. 138 | 139 | @return A matrix of the values corresponding to the Sobol sequence. 140 | */ 141 | + (instancetype)sobolSequenceLowerBound:(Matrix *)lower 142 | upperBound:(Matrix *)upper 143 | count:(int)count; 144 | 145 | /** 146 | Returns a matrix of quasi-random values according to the Halton sequence. 147 | The parameter matrices should have the same dimensions, and the resulting 148 | matrix will also be of the same dimensions as the parameters. 149 | 150 | @param lower Matrix containing values for the lower bounds. 151 | @param upper Matrix containing values for the upper bounds. 152 | @param count The number of points to sample. 153 | 154 | @return A matrix of the values corresponding to the Halton sequence. 155 | */ 156 | + (instancetype)haltonSequenceWithLowerBound:(Matrix *)lower 157 | upperBound:(Matrix *)upper 158 | count:(int)count; 159 | 160 | /** 161 | Returns the pseudo-inverse of the receiver. 162 | The calculation is performed using Singular Value Decomposition. 163 | 164 | @return The pseudo-inverse of the receiver. 165 | */ 166 | - (Matrix *)pseudoInverse; 167 | 168 | /** 169 | Performs Singular Value Decomposition on the receiver. 170 | 171 | @return An NSDictionary containing the "U", "S", "V" components of the SVD of the receiver. 172 | 173 | @warning As a matter of efficiency, and because the corresponding LAPACK function requires 174 | column-major matrices, the output dictionary will contain the "V" matrix, and not 175 | it's transpose. 176 | */ 177 | - (NSDictionary *)SVD; 178 | 179 | /** 180 | Returns the X vector that is the solution to the linear system A * X = B, with the receiver being A. 181 | 182 | @param B The matrix B. 183 | 184 | @return The solution vector X. 185 | */ 186 | - (Matrix *)solve:(Matrix *)B; 187 | 188 | /** 189 | Performs an in-place Cholesky decomposition on the receiver. 190 | Makes lower triangular R such that R * R' = self. Modifies self. 191 | */ 192 | - (void)cholesky; 193 | 194 | /** 195 | Returns a new matrix by performing Cholesky decomposition on the receiver. 196 | Makes lower triangular R such that R * R' = self. 197 | 198 | @return The matrix resulting from the Cholesky decomposition of the receiver. 199 | */ 200 | - (Matrix *)matrixByCholesky; 201 | 202 | /** 203 | Returns a row matrix containing the real Eigenvalues of the receiver. 204 | 205 | @return The resulting row matrix. 206 | */ 207 | - (Matrix *)realEigenvalues; 208 | 209 | /** 210 | Returns an NSDictionary with the results of performing an Eigenvalue decomposition on the receiver. 211 | 212 | @return A dictionary with the following key/value assignments: 213 | "Real Eigenvalues" : nx1 vector containing the matrix real eigenvalues. 214 | "Imaginary Eigenvalues" : nx1 vector containing the matrix imaginary eigenvalues. 215 | "Left Eigenvectors" : nxn matrix containing the matrix left eigenvectors, one per row. 216 | "Right Eigenvectors" : nxn matrix containing the matrix right eigenvectors, one per row. 217 | 218 | @warning The eigenvectors appear per ROW in the result. If you wish to obtain per column 219 | results, yuo need to transpose the resulting eigenvector matrix. 220 | */ 221 | - (NSDictionary *)eigenvectorsAndEigenvalues; 222 | 223 | /** 224 | Returns the determinant of the receiver. 225 | 226 | @return A double value corresponsing to the determinant of the receiver. 227 | 228 | @warning This method has not been extensively tested and may contain serious flaws. 229 | */ 230 | - (double)determinant; 231 | 232 | /** 233 | Returns a column matrix containing the sums of the rows of the receiver. 234 | 235 | @return The column matrix containing the sums of rows. 236 | */ 237 | - (Matrix *)sumsOfRows; 238 | 239 | /** 240 | Returns a row matrix containing the sums of the columns of the receiver. 241 | 242 | @return The row matrix containing the sums of columns. 243 | */ 244 | - (Matrix *)sumsOfColumns; 245 | 246 | /** 247 | Returns a column matrix containing the means of the rows of the receiver. 248 | 249 | @return The column matrix containing the means of rows. 250 | */ 251 | - (Matrix *)meansOfRows; 252 | 253 | /** 254 | Returns a row matrix containing the means of the columns of the receiver. 255 | 256 | @return The row matrix containing the means of columns. 257 | */ 258 | - (Matrix *)meansOfColumns; 259 | 260 | /** 261 | Returns a column matrix containing the population variances of the rows of the receiver. 262 | 263 | @return The column matrix containing the variances of rows. 264 | 265 | @warning This calculates the population variance. 266 | */ 267 | - (Matrix *)variancesOfRows; 268 | 269 | /** 270 | Returns a row matrix containing the population variances of the columns of the receiver. 271 | 272 | @return The row matrix containing the variances of columns. 273 | 274 | @warning This calculates the population variance. 275 | */ 276 | - (Matrix *)variancesOfColumns; 277 | 278 | /** 279 | Returns a column matrix containing the sample variances of the rows of the receiver. 280 | 281 | @return The column matrix containing the variances of rows. 282 | 283 | @warning This calculates the sample variance. 284 | */ 285 | - (Matrix *)sampleVariancesOfRows; 286 | 287 | /** 288 | Returns a row matrix containing the sample variances of the columns of the receiver. 289 | 290 | @return The row matrix containing the variances of columns. 291 | 292 | @warning This calculates the sample variance. 293 | */ 294 | - (Matrix *)sampleVariancesOfColumns; 295 | 296 | /** 297 | Returns a column matrix containing the minimum values of each row of the receiver. 298 | 299 | @return The column matrix containing the minimum values of each row. 300 | */ 301 | - (Matrix *)minimumsOfRows; 302 | 303 | /** 304 | Returns a column matrix containing the maximum values of each row of the receiver. 305 | 306 | @return The column matrix containing the maximum values of each row. 307 | */ 308 | - (Matrix *)maximumsOfRows; 309 | 310 | /** 311 | Returns a row matrix containing the minimum values of each column of the receiver. 312 | 313 | @return The row matrix containing the minimum values of each column. 314 | */ 315 | - (Matrix *)minimumsOfColumns; 316 | 317 | /** 318 | Returns a row matrix containing the maximum values of each column of the receiver. 319 | 320 | @return The row matrix containing the maximum values of each column. 321 | */ 322 | - (Matrix *)maximumsOfColumns; 323 | 324 | /** 325 | Returns a new matrix with each cell being the result of applying a function to 326 | the corresponding cell of the receiver. 327 | 328 | @param function The function to apply. 329 | 330 | @return The matrix of transformed values. 331 | */ 332 | - (Matrix *)matrixByApplyingFunction:(double (^)(double value))function; 333 | 334 | /** 335 | Applies a function to each cell of the receiver. 336 | 337 | @param function The function to apply. 338 | */ 339 | - (void)applyFunction:(double (^)(double value))function; 340 | 341 | /** 342 | Returns the multidimensional Euclidean distance of the receiver to another matrix. 343 | 344 | @param other The matrix to claculate the distance to. 345 | 346 | @return The calculated distance. 347 | 348 | @warning This method will accept any kind of matrix as parameter, as long as the 349 | dimensions are equal. 350 | 351 | */ 352 | - (double)euclideanDistanceTo:(Matrix *)other; 353 | 354 | /** 355 | Returns the multidimensional Quadrance (square of Euclidean distance of the receiver to another matrix. 356 | 357 | @param other The matrix to claculate the quadrance to. 358 | 359 | @return The calculated quadrance. 360 | 361 | @warning This method will accept any kind of matrix as parameter, as long as the 362 | dimensions are equal. 363 | 364 | */ 365 | - (double)quadranceTo:(Matrix *)other; 366 | 367 | /** 368 | Replaces values of the receiver with zeroes or ones, depending on the probability expressed by 369 | the existing values in the receiver. 370 | */ 371 | - (void)bernoulli; 372 | 373 | @end 374 | -------------------------------------------------------------------------------- /YCMatrix/Matrix+Manipulate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix+Manipulate.h 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import "Matrix.h" 29 | 30 | /** 31 | Manipulate is a category to the Matrix class that extends it 32 | by exposing functionality related to manipulating rows and columns, 33 | splitting and joining, sampling, shuffling, and a few others. 34 | */ 35 | @interface Matrix (Manipulate) 36 | 37 | /** 38 | Initializes and returns a new matrix from an NSArray of row matrices. 39 | 40 | @param rows The NSArray containing row matrix objects. 41 | 42 | @return A new matrix resulting from merging the rows. 43 | */ 44 | + (Matrix *)matrixFromRows:(NSArray *)rows; 45 | 46 | /** 47 | Initializes and returns a new matrix from an NSArray of column matrices. 48 | 49 | @param rows The NSArray containing column matrix objects. 50 | 51 | @return A new matrix resulting from merging the column. 52 | */ 53 | + (Matrix *)matrixFromColumns:(NSArray *)columns; 54 | 55 | /** 56 | Copy all the values of the matrix passed as the argument, to the receiver. 57 | 58 | @param matrix The matrix to copy the values from. 59 | */ 60 | - (void)copyValuesFrom:(Matrix *)aMatrix; 61 | 62 | /** 63 | Returns a row matrix with the contents of row |rowNumber|. 64 | 65 | @param rowNumber The index of the row to copy. 66 | 67 | @return The row matrix. 68 | */ 69 | - (Matrix *)row:(int)rowIndex; 70 | 71 | /** 72 | Returns a row matrix by referencing the contents of row |rowNumber|. 73 | 74 | @param rowIndex The index of the row to copy 75 | 76 | @return The row referencing matrix. 77 | 78 | @warning The returned matrix does not retain it's data. 79 | */ 80 | - (Matrix *)rowReference:(int)rowIndex; 81 | 82 | /** 83 | Returns a column (vector) matrix by referencing the contents of row |rowNumber|. 84 | 85 | @param rowIndex The index of the row to copy 86 | 87 | @return The referencing vector. 88 | 89 | @warning The returned matrix does not retain it's data. 90 | */ 91 | - (Matrix *)rowReferenceVector:(int)rowIndex; 92 | 93 | /** 94 | Returns a new matrix with the contents of the rows at the specified indexes. 95 | 96 | @param indexes The indexes of the rows. 97 | 98 | @return The matrix containing the specified rows. 99 | */ 100 | - (Matrix *)rows:(NSIndexSet *)indexes; 101 | 102 | /** 103 | Replaces the values of row |rowIndex| with those of row matrix |rowValue| 104 | 105 | @param rowIndex The index of the row to replace. 106 | @param rowValue The values to replace with. 107 | */ 108 | - (void)setRow:(int)rowIndex value:(Matrix *)rowValue; 109 | 110 | /** 111 | Returns an NSArray of row matrices, each representing one row of the receiver. 112 | 113 | @return The NSArray of row matrices. 114 | */ 115 | - (NSArray *)rowsAsNSArray; 116 | 117 | /** 118 | Row-wise splits the receiver at the specified indexes. 119 | 120 | @param indexes The splitting indexes. 121 | 122 | @return An NSArray containing the split segments. 123 | */ 124 | - (NSArray *)rowWiseSplitAtIndexes:(NSIndexSet *)indexes; 125 | 126 | /** 127 | Partitions the receiver into row chunks of size s. 128 | 129 | @param s The size of each row chunk. 130 | 131 | @return The NSArray of matrices resulting from the partitioning. 132 | */ 133 | - (NSArray *)rowWisePartition:(int)size; 134 | 135 | /** 136 | Returns the values of column |colIndex| as a column matrix. 137 | 138 | @param colIndex The index of the column 139 | 140 | @return The column matrix with the values of the column |colIndex|. 141 | */ 142 | - (Matrix *)column:(int)colIndex; 143 | 144 | /** 145 | Returns a new matrix with the contents of the columns at the specified indexes. 146 | 147 | @param indexes The indexes of the columns. 148 | 149 | @return The matrix containing the specified columns. 150 | */ 151 | - (Matrix *)columns:(NSIndexSet *)indexes; 152 | 153 | /** 154 | Replaces values of column |colIndex| with those of column matrix |columnValue| 155 | 156 | @param colNumber The index of the column to replace. 157 | @param columnValue The values to replace with. 158 | */ 159 | - (void)setColumn:(int)colNumber value:(Matrix *)columnValue; 160 | 161 | /** 162 | Creates column matrices from the columns of the matrix and returns them as an NSArray. 163 | 164 | @return The NSArray containing the columns of the receiver. 165 | */ 166 | - (NSArray *)columnsAsNSArray; 167 | 168 | /** 169 | Column-wise splits the receiver at the specified indexes. 170 | 171 | @param indexes The splitting indexes. 172 | 173 | @return An NSArray containing the split segments. 174 | */ 175 | - (NSArray *)columnWiseSplitAtIndexes:(NSIndexSet *)indexes; 176 | 177 | /** 178 | Partitions the receiver into column chunks of size s. 179 | 180 | @param s The size of each column chunk. 181 | 182 | @return The NSArray of matrices resulting from the partitioning. 183 | */ 184 | - (NSArray *)columnWisePartition:(int)size; 185 | 186 | /** 187 | Returns a matrix resulting from adding the values in the 188 | row matrix |row| to every row. 189 | 190 | @param row The row matrix whose values to add. 191 | 192 | @return The matrix after the addition. 193 | */ 194 | - (Matrix *)matrixByAddingRow:(Matrix *)row; 195 | 196 | /** 197 | Returns a matrix resulting from subtracting the values in 198 | row matrix |row| from every row. 199 | 200 | @param row The row matrix whose values to subtract. 201 | 202 | @return The matrix after the subtraction. 203 | */ 204 | - (Matrix *)matrixBySubtractingRow:(Matrix *)row; 205 | 206 | /** 207 | Returns a matrix resulting from multiplying the values in 208 | row matrix |row| with every row. 209 | 210 | @param row The row matrix whose values to multiply with. 211 | 212 | @return The matrix after the multiplication 213 | */ 214 | - (Matrix *)matrixByMultiplyingWithRow:(Matrix *)row; 215 | 216 | /** 217 | Returns a matrix resulting from adding the values in the 218 | column matrix |column| to every column. 219 | 220 | @param column The column matrix whose values to add. 221 | 222 | @return The matrix after the addition. 223 | */ 224 | - (Matrix *)matrixByAddingColumn:(Matrix *)column; 225 | 226 | /** 227 | Returns a matrix resulting from subtracting the values in 228 | column matrix |column| from every column. 229 | 230 | @param column The rocolumnw matrix whose values to subtract. 231 | 232 | @return The matrix after the subtraction. 233 | */ 234 | - (Matrix *)matrixBySubtractingColumn:(Matrix *)column; 235 | 236 | /** 237 | Returns a matrix resulting from multiplying the values in 238 | column matrix |column| with every column. 239 | 240 | @param column The column matrix whose values to multiply with. 241 | 242 | @return The matrix after the multiplication 243 | */ 244 | - (Matrix *)matrixByMultiplyingWithColumn:(Matrix *)column; 245 | 246 | /** 247 | Returns a new matrix with the values of the columns 248 | whose indices are in |range|. 249 | 250 | @param range The range of indices of columns to include. 251 | 252 | @return The matrix of columns in |range|. 253 | */ 254 | - (Matrix *)matrixWithColumnsInRange:(NSRange)range; 255 | 256 | /** 257 | Returns a new matrix with the values of the rows 258 | whose indices are in |range|. 259 | 260 | @param range The range of indices of rows to include. 261 | 262 | @return The matrix of rows in |range|. 263 | */ 264 | - (Matrix *)matrixWithRowsInRange:(NSRange)range; 265 | 266 | /** 267 | Adds row matrix |row| to every row of the receiver. 268 | 269 | @param row The row matrix to add 270 | */ 271 | - (void)addRow:(Matrix *)row; 272 | 273 | /** 274 | Subtracts row matrix |row| from every row of the receiver. 275 | 276 | @param row The row matrix to subtract 277 | */ 278 | - (void)subtractRow:(Matrix *)row; 279 | 280 | /** 281 | Multiplies row matrix |row| with every row of the receiver. 282 | 283 | @param row The row matrix to multiply 284 | */ 285 | - (void)multiplyRow:(Matrix *)row; 286 | 287 | /** 288 | Divides every row of the receiver with row matrix |row|. 289 | 290 | @param row The row matrix to multiply 291 | */ 292 | - (void)divideRow:(Matrix *)row; 293 | 294 | /** 295 | Adds column matrix |column| to every column of the receiver. 296 | 297 | @param column The column matrix to add 298 | */ 299 | - (void)addColumn:(Matrix *)column; 300 | 301 | /** 302 | Subtracts column matrix |column| from every column of the receiver. 303 | 304 | @param column The column matrix to subtract 305 | */ 306 | - (void)subtractColumn:(Matrix *)column; 307 | 308 | /** 309 | Multiplies column matrix |column| with every column of the receiver. 310 | 311 | @param column The column matrix to multiply 312 | */ 313 | - (void)multiplyColumn:(Matrix *)column; 314 | 315 | /** 316 | Divides every column of the receiver with column matrix |column|. 317 | 318 | @param column The column matrix to multiply 319 | */ 320 | - (void)divideColumn:(Matrix *)column; 321 | 322 | /** 323 | Returns a new matrix by appending row matrix |row|. 324 | 325 | @param row The row matrix to append. 326 | 327 | @return The result of appending. 328 | */ 329 | - (Matrix *)appendRow:(Matrix *)row; 330 | 331 | /** 332 | Returns a new matrix by appending column matrix |column|. 333 | 334 | @param column The column matrix to append. 335 | 336 | @return The result of appending. 337 | */ 338 | - (Matrix *)appendColumn:(Matrix *)column; 339 | 340 | /** 341 | Returns a new matrix that is the result of removing 342 | the row at |rowIndex|. 343 | 344 | @param rowIndex The index of the row to remove. 345 | 346 | @return The matrix missing the removed row. 347 | */ 348 | - (Matrix *)removeRow:(int)rowIndex; 349 | 350 | /** 351 | Returns a new matrix that is the result of removing 352 | the column at |columnIndex|. 353 | 354 | @param columnIndex The index of the column to remove. 355 | 356 | @return The matrix missing the removed column. 357 | */ 358 | - (Matrix *)removeColumn:(int)columnIndex; 359 | 360 | /** 361 | Returns a matrix resulting from appending a row with values |value| 362 | 363 | @param value The value of the row matrix to append. 364 | 365 | @return The matrix after appending. 366 | */ 367 | - (Matrix *)appendValueAsRow:(double)value; 368 | 369 | 370 | - (void)applyMatrix:(Matrix *)other i:(int)i j:(int)j; 371 | 372 | /** 373 | Returns a matrix with shuffled rows 374 | 375 | @return The matrix after shuffling rows. 376 | */ 377 | - (Matrix *)matrixByShufflingRows; 378 | 379 | /** 380 | Shuffles the rows of the receiver. 381 | */ 382 | - (void)shuffleRows; 383 | 384 | /** 385 | Returns a matrix with shuffled columns. 386 | 387 | @return The matrix after shuffling columns. 388 | */ 389 | - (Matrix *)matrixByShufflingColumns; 390 | 391 | /** 392 | Shuffles the columns of the receiver. 393 | */ 394 | - (void)shuffleColumns; 395 | 396 | /** 397 | Returns a matrix resulting from uniform random sampling of |sampleCount| 398 | rows, optionally with |replacement|. 399 | 400 | @param sampleCount The number of rows to sample. 401 | @param replacement Whether to use replacement in sampling. 402 | 403 | @return The matrix resulting from the sampling. 404 | */ 405 | - (Matrix *)matrixBySamplingRows:(NSUInteger)sampleCount replacement:(BOOL)replacement; 406 | 407 | /** 408 | Returns a matrix resulting from uniform random sampling of |sampleCount| 409 | columns, optionally with |replacement|. 410 | 411 | @param sampleCount The number of columns to sample. 412 | @param replacement Whether to use replacement in sampling. 413 | 414 | @return The matrix resulting from the sampling. 415 | */ 416 | - (Matrix *)matrixBySamplingColumns:(NSUInteger)sampleCount replacement:(BOOL)replacement; 417 | 418 | @end 419 | -------------------------------------------------------------------------------- /YCMatrix/Matrix+Manipulate.m: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix+Manipulate.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "Matrix+Manipulate.h" 28 | #import "Constants.h" 29 | 30 | #define ARC4RANDOM_MAX 0x100000000 31 | 32 | @implementation Matrix (Manipulate) 33 | 34 | + (Matrix *)matrixFromRows:(NSArray *)rows 35 | { 36 | NSUInteger rowCount = [rows count]; 37 | if (rowCount == 0) return [Matrix matrixOfRows:0 columns:0]; 38 | Matrix *firstRow = rows[0]; 39 | int columnCount = firstRow->columns; 40 | Matrix *ret = [Matrix matrixOfRows:(int)rowCount columns:(int)columnCount]; 41 | for (int i=0; imatrix[j] row:i column:j]; 47 | } 48 | } 49 | return ret; 50 | } 51 | 52 | + (Matrix *)matrixFromColumns:(NSArray *)columns 53 | { 54 | NSUInteger columnCount = [columns count]; 55 | if (columnCount == 0) return [Matrix matrixOfRows:0 columns:0]; 56 | Matrix *firstCol = columns[0]; 57 | int rowCount = firstCol->rows; 58 | Matrix *ret = [Matrix matrixOfRows:(int)rowCount columns:(int)columnCount]; 59 | for (int i=0; imatrix[j] row:j column:i]; 65 | } 66 | } 67 | return ret; 68 | } 69 | 70 | - (void)copyValuesFrom:(Matrix *)aMatrix 71 | { 72 | NSAssert(aMatrix.rows == self.rows && aMatrix.columns == self.columns, @"Incorrect matrix size"); 73 | memcpy(self->matrix, aMatrix->matrix, self.rows * self.columns * sizeof(double)); 74 | } 75 | 76 | - (Matrix *)row:(int) rowIndex 77 | { 78 | NSAssert(rowIndex < self->rows, @"Index out of bounds"); 79 | // http://stackoverflow.com/questions/5850000/how-to-split-array-into-two-arrays-in-c 80 | int startIndex = rowIndex * self->columns; 81 | Matrix *rowmatrix = [Matrix matrixOfRows:1 columns:self->columns]; 82 | double *row = rowmatrix->matrix; 83 | memcpy(row, self->matrix + startIndex, self->columns * sizeof(double)); 84 | return rowmatrix; 85 | } 86 | 87 | - (Matrix *)rowReference:(int)rowIndex 88 | { 89 | NSAssert(rowIndex < self->rows, @"Index out of bounds"); 90 | int startIndex = rowIndex * self->columns; 91 | return [Matrix matrixFromArray:self->matrix+startIndex rows:1 92 | columns:self->columns mode:YCMWeak]; 93 | } 94 | 95 | - (Matrix *)rowReferenceVector:(int)rowIndex 96 | { 97 | NSAssert(rowIndex < self->rows, @"Index out of bounds"); 98 | int startIndex = rowIndex * self->columns; 99 | return [Matrix matrixFromArray:self->matrix+startIndex rows:self->columns 100 | columns:1 mode:YCMWeak]; 101 | } 102 | 103 | - (Matrix *)rows:(NSIndexSet *)indexes 104 | { 105 | NSAssert([indexes lastIndex] < self->rows, @"Index out of bounds"); 106 | __block int count = 0; 107 | Matrix *result = [Matrix matrixOfRows:(int)[indexes count] columns:self.columns]; 108 | [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 109 | [result setRow:count++ value:[self row:(int)idx]]; 110 | }]; 111 | return result; 112 | } 113 | 114 | - (void)setRow:(int)rowIndex value:(Matrix *)rowValue 115 | { 116 | NSAssert(rowIndex < self->rows, @"Index out of bounds"); 117 | NSAssert(rowValue->rows == 1 && rowValue->columns == columns, @"Matrix size mismatch"); 118 | memcpy(self->matrix + columns * rowIndex, rowValue->matrix, columns * sizeof(double)); 119 | } 120 | 121 | - (NSArray *)rowsAsNSArray 122 | { 123 | NSMutableArray *rowsArray = [NSMutableArray arrayWithCapacity:rows]; 124 | for (int i=0; i 0) 155 | { 156 | partitions++; 157 | } 158 | NSMutableArray *result = [NSMutableArray array]; 159 | for (int i=0; i 0) 163 | { 164 | sLim = remainder; 165 | } 166 | NSRange partitionRange = NSMakeRange(i * size, sLim); 167 | Matrix *partition = [self rows:[NSIndexSet indexSetWithIndexesInRange:partitionRange]]; 168 | [result addObject:partition]; 169 | } 170 | return result; 171 | } 172 | 173 | - (Matrix *)column:(int) colIndex 174 | { 175 | NSAssert(colIndex < self->columns, @"Index out of bounds"); 176 | Matrix *columnmatrix = [Matrix matrixOfRows:self->rows columns:1]; 177 | double *column = columnmatrix->matrix; 178 | for (int i=0; irows; i++) 179 | { 180 | column[i] = self->matrix[i*self->columns + colIndex]; 181 | } 182 | return columnmatrix; 183 | } 184 | 185 | - (Matrix *)columns:(NSIndexSet *)indexes 186 | { 187 | NSAssert([indexes lastIndex] < self->columns, @"Index out of bounds"); 188 | __block int count = 0; 189 | Matrix *result = [Matrix matrixOfRows:self.rows columns:(int)[indexes count]]; 190 | [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 191 | [result setColumn:count++ value:[self column:(int)idx]]; 192 | }]; 193 | return result; 194 | } 195 | 196 | - (void)setColumn:(int)colIndex value:(Matrix *)columnValue 197 | { 198 | NSAssert(colIndex < self->columns, @"Index out of bounds"); 199 | NSAssert(columnValue->columns == 1 && columnValue->rows == rows, @"Matrix size mismatch"); 200 | for (int i=0; imatrix[columns*i + colIndex] = columnValue->matrix[i]; 203 | } 204 | } 205 | 206 | - (NSArray *)columnsAsNSArray // needs some speed improvement 207 | { 208 | NSMutableArray *columnsArray = [NSMutableArray arrayWithCapacity:columns]; 209 | for (int i=0; i 0) 240 | { 241 | partitions++; 242 | } 243 | NSMutableArray *result = [NSMutableArray array]; 244 | for (int i=0; i 0) 248 | { 249 | sLim = remainder; 250 | } 251 | NSRange partitionRange = NSMakeRange(i * size, sLim); 252 | Matrix *partition = [self columns:[NSIndexSet indexSetWithIndexesInRange:partitionRange]]; 253 | [result addObject:partition]; 254 | } 255 | return result; 256 | } 257 | 258 | - (Matrix *)matrixByAddingRow:(Matrix *)row 259 | { 260 | Matrix *result = [self copy]; 261 | [result addRow:row]; 262 | return result; 263 | } 264 | 265 | - (Matrix *)matrixBySubtractingRow:(Matrix *)row 266 | { 267 | Matrix *result = [self copy]; 268 | [result subtractRow:row]; 269 | return result; 270 | } 271 | 272 | - (Matrix *)matrixByMultiplyingWithRow:(Matrix *)row 273 | { 274 | Matrix *result = [self copy]; 275 | [result multiplyRow:row]; 276 | return result; 277 | } 278 | 279 | - (Matrix *)matrixByAddingColumn:(Matrix *)column 280 | { 281 | Matrix *result = [self copy]; 282 | [result addColumn:column]; 283 | return result; 284 | } 285 | 286 | - (Matrix *)matrixBySubtractingColumn:(Matrix *)column 287 | { 288 | Matrix *result = [self copy]; 289 | [result subtractColumn:column]; 290 | return result; 291 | } 292 | 293 | - (Matrix *)matrixByMultiplyingWithColumn:(Matrix *)column 294 | { 295 | Matrix *result = [self copy]; 296 | [result multiplyColumn:column]; 297 | return result; 298 | } 299 | 300 | - (Matrix *)matrixWithRowsInRange:(NSRange)range 301 | { 302 | NSAssert(range.location + range.length <= self->rows, @"Input out of bounds"); 303 | int valueOffset = (int)range.location * self->columns; 304 | int valueCount = (int)range.length * self->columns; 305 | 306 | Matrix *newMatrix = [Matrix matrixOfRows:(int)range.length columns:self->columns]; 307 | memcpy(newMatrix->matrix, self->matrix+valueOffset, valueCount * sizeof(double)); 308 | 309 | return newMatrix; 310 | } 311 | 312 | - (Matrix *)matrixWithColumnsInRange:(NSRange)range 313 | { 314 | NSAssert(range.location + range.length <= self->columns, @"Input out of bounds"); 315 | int rowOffset = (int)range.location; 316 | int rowLength = (int)range.length; 317 | 318 | Matrix *newMatrix = [Matrix matrixOfRows:self->rows columns:rowLength]; 319 | 320 | for (int i=0; irows; i++) 321 | { 322 | memcpy(newMatrix->matrix + i*rowLength, 323 | self->matrix + rowOffset + i*self->columns, 324 | rowLength * sizeof(double)); 325 | } 326 | return newMatrix; 327 | } 328 | 329 | - (void)addRow:(Matrix *)row 330 | { 331 | NSAssert(row->rows == 1 && row->columns == self->columns, @"Matrix size mismatch"); 332 | double *sumarray = self->matrix; 333 | double *addendarray = row->matrix; 334 | int cols = self->columns; 335 | int rws = self->rows; 336 | for (int i=0; irows == 1 && row->columns == self->columns, @"Matrix size mismatch"); 348 | double *subtractedarray = self->matrix; 349 | double *subtrahendarray = row->matrix; 350 | int cols = self->columns; 351 | int rws = self->rows; 352 | for (int i=0; irows == 1 && row->columns == self->columns, @"Matrix size mismatch"); 364 | double *productarray = self->matrix; 365 | double *factorarray = row->matrix; 366 | int cols = self->columns; 367 | int rws = self->rows; 368 | for (int i=0; irows == 1 && row->columns == self->columns, @"Matrix size mismatch"); 380 | double *productarray = self->matrix; 381 | double *factorarray = row->matrix; 382 | int cols = self->columns; 383 | int rws = self->rows; 384 | for (int i=0; icolumns == 1 && column->rows == self->rows, @"Matrix size mismatch"); 397 | double *sumarray = self->matrix; 398 | double *addendarray = column->matrix; 399 | int cols = self->columns; 400 | int rws = self->rows; 401 | for (int i=0; icolumns == 1 && column->rows == self->rows, @"Matrix size mismatch"); 413 | double *subtractedarray = self->matrix; 414 | double *subtrahendarray = column->matrix; 415 | int cols = self->columns; 416 | int rws = self->rows; 417 | for (int i=0; icolumns == 1 && column->rows == self->rows, @"Matrix size mismatch"); 429 | double *productarray = self->matrix; 430 | double *factorarray = column->matrix; 431 | int cols = self->columns; 432 | int rws = self->rows; 433 | for (int i=0; icolumns == 1 && column->rows == self->rows, @"Matrix size mismatch"); 445 | double *productarray = self->matrix; 446 | double *factorarray = column->matrix; 447 | int cols = self->columns; 448 | int rws = self->rows; 449 | for (int i=0; irows == 1 && row->columns == self->columns, @"Matrix size mismatch"); 461 | double *newMatrix = malloc(columns * (rows + 1) * sizeof(double)); 462 | memcpy(newMatrix, self->matrix, columns * rows * sizeof(double)); 463 | memcpy(newMatrix + columns*rows, row->matrix, columns * sizeof(double)); 464 | return [Matrix matrixFromArray:newMatrix rows:rows + 1 columns:columns mode:YCMStrong]; 465 | } 466 | 467 | - (Matrix *)appendColumn:(Matrix *)column 468 | { 469 | NSAssert(column->columns == 1 && column->rows == self->rows, @"Matrix size mismatch"); 470 | double *newMatrix = malloc((columns + 1) * rows * sizeof(double)); 471 | int newCols = columns + 1; 472 | for (int i=0; i < rows; i++) 473 | { 474 | memcpy(newMatrix + newCols * i, self->matrix + columns * i, columns * sizeof(double)); 475 | newMatrix[newCols * i + columns] = column->matrix[i]; 476 | } 477 | return [Matrix matrixFromArray:newMatrix rows:rows columns:columns + 1 mode:YCMStrong]; 478 | } 479 | 480 | - (Matrix *)removeRow:(int)rowIndex 481 | { 482 | 483 | NSAssert(rowIndex < self->rows, @"Index out of bounds"); 484 | double newRows = rows - 1; 485 | double *newMatrix = malloc(columns * newRows * sizeof(double)); 486 | for (int i=0; i < newRows; i++) // should count to one-less than rows, so newRows 487 | { 488 | int idx = i >= rowIndex ? i+1 : i; 489 | memcpy(newMatrix + columns * i, self->matrix + columns * idx, columns * sizeof(double)); 490 | } 491 | return [Matrix matrixFromArray:newMatrix rows:newRows columns:columns]; 492 | } 493 | 494 | - (Matrix *)removeColumn:(int)columnIndex 495 | { 496 | NSAssert(columnIndex < self->columns, @"Index out of bounds"); 497 | int newCols = columns - 1; 498 | double *newMatrix = malloc(newCols * rows * sizeof(double)); 499 | for (int i=0; i < rows; i++) 500 | { 501 | memcpy(newMatrix + i*newCols, 502 | self->matrix + i*self->columns, 503 | columnIndex * sizeof(double)); 504 | memcpy(newMatrix + columnIndex + i*newCols, 505 | self->matrix + columnIndex + 1 + i*self->columns, 506 | (newCols - columnIndex) * sizeof(double)); 507 | } 508 | return [Matrix matrixFromArray:newMatrix rows:rows columns:newCols]; 509 | } 510 | 511 | - (Matrix *)appendValueAsRow:(double)value 512 | { 513 | NSAssert(columns == 1, @"Matrix size mismatch – Input needs to be a vector"); 514 | int newRows = rows + 1; 515 | double *newArray = malloc(columns * newRows * sizeof(double)); 516 | memcpy(newArray, matrix, columns * rows * sizeof(double)); 517 | newArray[columns * newRows - 1] = value; 518 | return [Matrix matrixFromArray:newArray rows:newRows columns:columns]; 519 | } 520 | 521 | - (void)applyMatrix:(Matrix *)other i:(int)i j:(int)j 522 | { 523 | NSAssert(other.rows + 1 <= self.rows && other.columns + j <= self.columns, 524 | @"Matrix out of bounds"); 525 | int ma = self.rows; 526 | int na = self.columns; 527 | int mo = other.rows; 528 | int no = other.columns; 529 | for (int io = 0; iomatrix[(io + i) * na + (jo + j)] = other->matrix[io * no + jo]; 534 | } 535 | } 536 | } 537 | 538 | // Fisher-Yates Inside-out Shuffle 539 | - (Matrix *)matrixByShufflingRows 540 | { 541 | Matrix *ret = [Matrix matrixFromMatrix:self]; 542 | int rowCount = self->rows; 543 | int colCount = self->columns; 544 | for (int i=0; imatrix[i*colCount + j] = ret->matrix[o*colCount + j]; 552 | ret->matrix[o*colCount + j] = self->matrix[i*colCount + j]; 553 | } 554 | } 555 | return ret; 556 | } 557 | 558 | // Fisher-Yates Shuffle 559 | - (void)shuffleRows 560 | { 561 | int rowCount = self->rows; 562 | int colCount = self->columns; 563 | double tmp; 564 | for (int i = rowCount - 1; i>=0; --i) 565 | { 566 | int o = arc4random_uniform((int)i); 567 | for (int j=0; jmatrix[i*colCount + j]; 571 | self->matrix[i*colCount + j] = self->matrix[o*colCount + j]; 572 | self->matrix[o*colCount + j] = tmp; 573 | } 574 | } 575 | } 576 | 577 | // Fisher-Yates Inside-out Shuffle (UNTESTED!) 578 | - (Matrix *)matrixByShufflingColumns 579 | { 580 | Matrix *ret = [Matrix matrixFromMatrix:self]; 581 | int rowCount = self->rows; 582 | int colCount = self->columns; 583 | for (int i=0; imatrix[j*colCount + i] = ret->matrix[j*colCount + o]; 589 | ret->matrix[j*colCount + o] = self->matrix[j*colCount + i]; 590 | } 591 | } 592 | return ret; 593 | } 594 | 595 | // Fisher-Yates Shuffle 596 | - (void)shuffleColumns 597 | { 598 | int rowCount = self->rows; 599 | int colCount = self->columns; 600 | double tmp; 601 | for (int i = colCount - 1; i>=0; --i) 602 | { 603 | int o = arc4random_uniform((int)i); 604 | for (int j=0; jmatrix[j*colCount + i]; 607 | self->matrix[j*colCount + i] = self->matrix[j*colCount + o]; 608 | self->matrix[j*colCount + o] = tmp; 609 | } 610 | } 611 | } 612 | 613 | - (Matrix *)matrixBySamplingRows:(NSUInteger)sampleCount replacement:(BOOL)replacement 614 | { 615 | int rowSize = self->rows; 616 | int colSize = self->columns; 617 | int colMemory = colSize * sizeof(double); 618 | Matrix *new = [Matrix matrixOfRows:(int)sampleCount columns:colSize]; 619 | if (replacement) 620 | { 621 | for (int i=0; irows); 624 | memcpy(new->matrix + i * colMemory, self->matrix + rnd * colMemory, colSize); 625 | } 626 | } 627 | else 628 | { 629 | // Knuth's S algorithm 630 | int i = 0; 631 | int n = (int)sampleCount; 632 | int samples = n; 633 | NSUInteger N = rowSize; 634 | while (n > 0) 635 | { 636 | if (N * (double)arc4random() / ARC4RANDOM_MAX <= n) 637 | { 638 | memcpy(new->matrix + (samples - n) * colMemory, self->matrix + i * colMemory, colSize); 639 | n--; 640 | } 641 | i++; 642 | N--; 643 | } 644 | } 645 | return new; 646 | } 647 | 648 | - (Matrix *)matrixBySamplingColumns:(NSUInteger)sampleCount replacement:(BOOL)replacement 649 | { 650 | int rowSize = self->rows; 651 | int colSize = self->columns; 652 | Matrix *new = [Matrix matrixOfRows:rowSize columns:(int)sampleCount]; 653 | if (replacement) 654 | { 655 | for (int i=0; irows); 658 | [new setColumn:i value:[self column:rnd]]; 659 | } 660 | } 661 | else 662 | { 663 | // Knuth's S algorithm 664 | int i = 0; 665 | int n = (int)sampleCount; 666 | int samples = n; 667 | NSUInteger N = colSize; 668 | while (n > 0) 669 | { 670 | if (N * (double)arc4random() / ARC4RANDOM_MAX <= n) 671 | { 672 | [new setColumn:samples - n value:[self column:i]]; 673 | n--; 674 | } 675 | i++; 676 | N--; 677 | } 678 | } 679 | return new; 680 | } 681 | 682 | @end 683 | -------------------------------------------------------------------------------- /YCMatrix/Matrix+Map.h: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix+Map.h 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import "Matrix.h" 29 | 30 | typedef enum _MapBasis : int16_t 31 | { 32 | StDev = 1, 33 | MinMax = 0 34 | } MapBasis; 35 | 36 | typedef struct _YCDomain 37 | { 38 | double location; 39 | double length; 40 | } YCDomain; 41 | 42 | static inline YCDomain YCMakeDomain(double loc, double len) 43 | { 44 | YCDomain d; 45 | d.location = loc; 46 | d.length = len; 47 | return d; 48 | } 49 | 50 | static inline NSUInteger YCMaxDomain(YCDomain domain) 51 | { 52 | return (domain.location + domain.length); 53 | } 54 | 55 | static inline BOOL YCNumberInDomain(double num, YCDomain domain) 56 | { 57 | return (!(num < domain.location) && (num - domain.location) < domain.length) ? YES : NO; 58 | } 59 | 60 | static inline BOOL YCEqualDomains(YCDomain domain1, YCDomain domain2) 61 | { 62 | return (domain1.location == domain2.location && domain1.length == domain2.length); 63 | } 64 | 65 | @interface Matrix (Map) 66 | 67 | /** 68 | Returns the result of a row-wise linear mapping of the receiver using the 69 | supplied mapping matrix. 70 | 71 | @param transform A two-column matrix describing the linear row-wise mapping. 72 | 73 | @return A matrix containing the mapped values. 74 | */ 75 | - (Matrix *)matrixByRowWiseMapUsing:(Matrix *)transform; 76 | 77 | /** 78 | Returns a two-column matrix that describes a linear row-wise mapping of the receiver 79 | to a supplied domain. 80 | 81 | @param domain The domain to map the rows to 82 | @param basis Whether to use min and max values for deriving the source domain, or the 83 | row values' standard deviation. 84 | 85 | @return A two-column descriptor matrix with the linear row-wise map coefficients 86 | */ 87 | - (Matrix *)rowWiseMapToDomain:(YCDomain)domain basis:(MapBasis)basis; 88 | 89 | /** 90 | Returns a two-column matrix that describes an inverse linear row-wise mapping of 91 | the receiver from a supplied domain. 92 | 93 | @param domain The domain to map the rows from. 94 | @param basis Whether to use min and max values for deriving the target domain, or the 95 | row values' standard deviation. 96 | 97 | @return A two-column descriptor matrix with the inverse linear row-wise map coefficients 98 | */ 99 | - (Matrix *)rowWiseInverseMapFromDomain:(YCDomain)domain basis:(MapBasis)basis; 100 | 101 | /** 102 | Returns the result of a column-wise linear mapping of the receiver using the 103 | supplied mapping matrix. 104 | 105 | @param transform A two-column matrix describing the linear column-wise mapping. 106 | 107 | @return A matrix containing the mapped values. 108 | */ 109 | - (Matrix *)matrixByColumnWiseMapUsing:(Matrix *)transform; 110 | 111 | /** 112 | Returns a two-column matrix that describes a linear column-wise mapping of the receiver 113 | to a supplied domain. 114 | 115 | @param domain The domain to map the column to. 116 | @param basis Whether to use min and max values for deriving the source domain, or the 117 | column values' standard deviation. 118 | 119 | @return A two-column descriptor matrix with the linear column-wise map coefficients 120 | */ 121 | - (Matrix *)columnWiseMapToDomain:(YCDomain)domain basis:(MapBasis)basis; 122 | 123 | /** 124 | Returns a two-column matrix that describes an inverse linear column-wise mapping of 125 | the receiver from a supplied domain. 126 | 127 | @param domain The domain to map the column from. 128 | @param basis Whether to use min and max values for deriving the target domain, or the 129 | column values' standard deviation. 130 | 131 | @return A two-column descriptor matrix with the inverse linear column-wise map coefficients 132 | */ 133 | - (Matrix *)columnWiseInverseMapFromDomain:(YCDomain)domain basis:(MapBasis)basis; 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /YCMatrix/Matrix+Map.m: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix+Map.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "Matrix+Map.h" 28 | #import "Matrix+Manipulate.h" 29 | 30 | @implementation Matrix (Map) 31 | 32 | - (Matrix *)matrixByRowWiseMapUsing:(Matrix *)transform 33 | { 34 | double *mtxArray = self->matrix; 35 | double *transformArray = transform->matrix; 36 | Matrix *transformed = [Matrix matrixOfRows:rows columns:columns]; 37 | double *transformedArray = transformed->matrix; 38 | dispatch_apply(rows, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t i) 39 | { 40 | double a = transformArray[2*i]; 41 | double b = transformArray[2*i + 1]; 42 | for (int j=0; jrows; 53 | int numColumns = self->columns; 54 | NSArray *matrixRows = [self rowsAsNSArray]; 55 | Matrix *transform = [Matrix matrixOfRows:numRows columns:2]; 56 | int i=0; 57 | double tmean = domain.location + domain.length * 0.5; 58 | double trange = domain.length; 59 | for (Matrix *m in matrixRows) 60 | { 61 | double a, b; 62 | double fmean = 0, frange = 0; 63 | for (int j=0; jmatrix[j]; 66 | } 67 | fmean /= numColumns; 68 | if (basis == StDev) 69 | { 70 | double fstdev = 0; 71 | for (int j=0; jmatrix[j] - fmean, 2); 74 | } 75 | fstdev = sqrt(fstdev/numColumns); 76 | frange = 2*fstdev; 77 | } 78 | else 79 | { 80 | double min = DBL_MAX; 81 | double max = -DBL_MAX; 82 | for (int j=0; jmatrix[j]); 85 | max = MAX(max, m->matrix[j]); 86 | } 87 | frange = max - min; 88 | } 89 | a = trange / frange; 90 | b = tmean - fmean * (trange / frange); 91 | [transform setValue:a row:i column:0]; 92 | [transform setValue:b row:i++ column:1]; 93 | } 94 | return transform; 95 | } 96 | 97 | - (Matrix *)rowWiseInverseMapFromDomain:(YCDomain)domain basis:(MapBasis)basis 98 | { 99 | int numRows = self->rows; 100 | int numColumns = self->columns; 101 | NSArray *matrixRows = [self rowsAsNSArray]; 102 | Matrix *transform = [Matrix matrixOfRows:numRows columns:2]; 103 | int i=0; 104 | double fmean = domain.location + domain.length * 0.5; 105 | double frange = domain.length; 106 | for (Matrix *m in matrixRows) 107 | { 108 | double a, b; 109 | double tmean = 0, trange = 0; 110 | for (int j=0; jmatrix[j]; 113 | } 114 | tmean /= numColumns; 115 | if (basis == StDev) 116 | { 117 | double tstdev = 0; 118 | for (int j=0; jmatrix[j] - tmean, 2); 121 | } 122 | tstdev = sqrt(tstdev/numColumns); 123 | trange = 2*tstdev; 124 | } 125 | else 126 | { 127 | double min = DBL_MAX; 128 | double max = -DBL_MAX; 129 | for (int j=0; jmatrix[j]); 132 | max = MAX(max, m->matrix[j]); 133 | } 134 | trange = max - min; 135 | } 136 | a = trange / frange; 137 | b = tmean - fmean * (trange / frange); 138 | [transform setValue:a row:i column:0]; 139 | [transform setValue:b row:i++ column:1]; 140 | } 141 | return transform; 142 | } 143 | 144 | 145 | - (Matrix *)matrixByColumnWiseMapUsing:(Matrix *)transform 146 | { 147 | // TODO: Reimplement to improve performance (remove extra transposition) 148 | return [[self matrixByTransposing] matrixByRowWiseMapUsing:transform]; 149 | } 150 | 151 | - (Matrix *)columnWiseMapToDomain:(YCDomain)domain basis:(MapBasis)basis 152 | { 153 | // TODO: Reimplement to improve performance (remove extra transposition) 154 | return [[self matrixByTransposing] rowWiseMapToDomain:domain basis:basis]; 155 | } 156 | 157 | - (Matrix *)columnWiseInverseMapFromDomain:(YCDomain)domain basis:(MapBasis)basis 158 | { 159 | // TODO: Reimplement to improve performance (remove extra transposition) 160 | return [[self matrixByTransposing] rowWiseInverseMapFromDomain:domain basis:basis]; 161 | } 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /YCMatrix/Matrix.h: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix.h 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | typedef enum refMode { YCMWeak, YCMStrong, YCMCopy } refMode; 28 | 29 | #import 30 | #import 31 | 32 | /** 33 | The Matrix class is the main class in the YCMatrix framework, 34 | which represents a single mxn matrix. 35 | */ 36 | @interface Matrix : NSObject 37 | { 38 | @public double *matrix; 39 | @public int rows; 40 | @public int columns; 41 | @private BOOL freeData; 42 | } 43 | 44 | /// @name Initialization 45 | 46 | /** 47 | Initializes and returns a new matrix of |m| rows and |n| columns. 48 | 49 | @param m Number of rows. 50 | @param n Number of columns. 51 | 52 | @return A new matrix of |m| rows and |n| columns. 53 | */ 54 | + (instancetype)matrixOfRows:(int)m columns:(int)n; 55 | 56 | /** 57 | Initializes and returns a new matrix with the same number of rows and columns as |other|. 58 | 59 | @param other The matrix whose number of rows and columns to clone. 60 | 61 | @return A new matrix with the same number of rows and columns as |other|. 62 | */ 63 | + (instancetype)matrixLike:(Matrix *)other; 64 | 65 | /** 66 | Initializes and returns a new matrix of ones with the same number of rows and columns as |other|. 67 | 68 | @param other The matrix whose number of rows and columns to clone. 69 | 70 | @return A new matrix of ones with the same number of rows and columns as |other|. 71 | */ 72 | + (instancetype)onesLike:(Matrix *)other; 73 | 74 | /** 75 | Initializes and returns a new matrix of |m| rows and |n| columns, each containing value |val|. 76 | 77 | @param m The number of rows. 78 | @param n The number of columns. 79 | @param val Cell value. 80 | 81 | @return A new matrix of |m| rows and |n| columns. 82 | */ 83 | + (instancetype)matrixOfRows:(int)m columns:(int)n value:(double)val; 84 | 85 | /** 86 | Initializes and returns a new matrix of |m| rows and |n| columns, with value |diagonal| 87 | representing values in the matrix diagonal, and each other cell containing value |val|. 88 | 89 | @param m The number of rows. 90 | @param n The number of columns. 91 | @param diagonal The value to insert to the diagonal. 92 | @param val The value to insert to the rest of the matrix. 93 | 94 | @return A new matrix of |m| rows and |n| columns. 95 | */ 96 | + (instancetype)matrixOfRows:(int)m 97 | columns:(int)n 98 | valueInDiagonal:(double)diagonal 99 | value:(double)val; 100 | 101 | /** 102 | Initializes and returns a new matrix of |m| rows and |n| columns, with values in array |diagonal| 103 | representing values in the matrix diagonal, and each other cell containing value |val|. 104 | 105 | @param m The number of rows. 106 | @param n The number of columns. 107 | @param diagonal The values to insert to the diagonal. 108 | @param val The value to insert to the rest of the matrix. 109 | 110 | @return A new matrix of |m| rows and |n| columns. 111 | */ 112 | + (instancetype)matrixOfRows:(int)m 113 | columns:(int)n 114 | valuesInDiagonal:(double *)diagonal 115 | value:(double)val; 116 | 117 | /** 118 | Initializes and returns a new matrix of |m| rows and |n| columns, 119 | by copying array |arr|. 120 | 121 | @param arr The array of values. 122 | @param m The number of rows. 123 | @param n The number of columns. 124 | 125 | @return A new matrix of |m| rows and |n| columns. 126 | */ 127 | + (instancetype)matrixFromArray:(double *)arr rows:(int)m columns:(int)n; 128 | 129 | /** 130 | Initializes and returns a new matrix of |m| rows and |n| columns, 131 | by either weakly or strongly referencing, or copying array |arr|. 132 | 133 | @param arr The array of values. 134 | @param m The number of rows. 135 | @param n The number of columns. 136 | @param mode The reference mode. 137 | 138 | @return A new matrix of |m| rows and |n| columns. 139 | */ 140 | + (instancetype)matrixFromArray:(double *)arr rows:(int)m columns:(int)n mode:(refMode)mode; 141 | 142 | /** 143 | Initializes and returns a new matrix of |m| rows and |n| columns, 144 | by copying values in NSArray |arr| 145 | 146 | @param arr The NSArray containing values to be copied. 147 | @param m The number of rows. 148 | @param n The number of columns. 149 | 150 | @return A new matrix of |m| rows and |n| columns. 151 | */ 152 | + (instancetype)matrixFromNSArray:(NSArray *)arr rows:(int)m columns:(int)n; 153 | 154 | /** 155 | Initializes and returns a new matrix by copying matrix |other|. 156 | 157 | @param other The matrix to copy. 158 | 159 | @return A new matrix of equal dimensions to |other|. 160 | */ 161 | + (instancetype)matrixFromMatrix:(Matrix *)other; 162 | 163 | /** 164 | Initializes and returns a new Identity matrix of |m| rows and |n| columns 165 | 166 | @param m The number of rows. 167 | @param n The number of columns. 168 | 169 | @return A new matrix of |m| rows and |n| columns. 170 | */ 171 | + (instancetype)identityOfRows:(int)m columns:(int)n; 172 | 173 | 174 | /// @name Accessing and setting data 175 | 176 | /** 177 | Returns the value at position |row|, |column| of the receiver. 178 | 179 | @param row The row. 180 | @param column The column. 181 | 182 | @return A double corresponding to the value at position |row|, |column|. 183 | */ 184 | - (double)valueAtRow:(int)row column:(int)column; 185 | 186 | /** 187 | Returns the value at position |i|, |j| of the receiver. 188 | 189 | @param i The row. 190 | @param j The column. 191 | 192 | @return A double corresponding to the value at position |i|, |j|. 193 | */ 194 | - (double)i:(int)i j:(int)j; 195 | 196 | /** 197 | Sets value |value| at |row|, |column| of the receiver. 198 | 199 | @param value The value to set. 200 | @param row The row. 201 | @param column The column. 202 | */ 203 | - (void)setValue:(double)value row:(int)row column:(int)column; 204 | 205 | /** 206 | Sets value |value| at |i|, |j| of the receiver. 207 | 208 | @param i The row. 209 | @param j The column. 210 | @param value The value to set. 211 | */ 212 | - (void)i:(int)i j:(int)j set:(double)value; 213 | 214 | /** 215 | Increments value at |i|, |j| of the receiver, by |value|. 216 | 217 | @param i The row. 218 | @param j The column. 219 | @param value The value to set. 220 | */ 221 | - (void)i:(int)i j:(int)j increment:(double)value; 222 | 223 | /** 224 | Increments all values in the matrix by |value|. 225 | 226 | @param value The value to increment by. 227 | */ 228 | - (void)incrementAll:(double)value; 229 | 230 | /// @name Matrix Operations 231 | 232 | /** 233 | Returns the result of adding the matrix to |addend|. 234 | 235 | @param addend The matrix to add to. 236 | 237 | @return The result of the addition. 238 | */ 239 | - (Matrix *)matrixByAdding:(Matrix *)addend; 240 | 241 | /** 242 | Returns the result of subtracting |subtrahend| from the receiver. 243 | 244 | @param subtrahend The matrix to subtract from this. 245 | 246 | @return The result of the subtraction. 247 | */ 248 | - (Matrix *)matrixBySubtracting:(Matrix *)subtrahend; 249 | 250 | /** 251 | Returns the result of multiplying the receiver with right matrix |mt|. 252 | 253 | @param mt The matrix to multiply with. 254 | 255 | @return The result of the multiplication. 256 | */ 257 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt; 258 | 259 | /** 260 | Returns the result of multiplying the receiver with right matrix |mt| and optionally transposing 261 | the result. 262 | 263 | @param mt The matrix to multiply with. 264 | @param trans Whether to transpose the result. 265 | 266 | @return The result of the operation. 267 | */ 268 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt AndTransposing:(bool)trans; 269 | 270 | /** 271 | Returns the result of multiplying the receiver with right matrix |mt| and adding 272 | YCMatrix |ma| to the result. 273 | 274 | @param mt The matrix to multiply with. 275 | @param ma The matrix to add to the multiplication result. 276 | 277 | @return The result of the operation. 278 | */ 279 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt AndAdding:(Matrix *)ma; 280 | 281 | /** 282 | Returns the result of multiplying the receiver with right matrix |mt| and then with scalar |factor|. 283 | 284 | @param mt The matrix to multiply with. 285 | @param sf The scalar factor to multiply with. 286 | 287 | @return The result of the multiplication. 288 | */ 289 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt AndFactor:(double)sf; 290 | 291 | /** 292 | Returns the result of transposing the receiver and multiplying with right matrix |mt|. 293 | 294 | @param mt The matrix to multiply with. 295 | 296 | @return The result of the operation. 297 | */ 298 | - (Matrix *)matrixByTransposingAndMultiplyingWithRight:(Matrix *)mt; 299 | 300 | /** 301 | Returns the result of transposing the receiver and multiplying with left matrix |mt|. 302 | 303 | @param mt The matrix to multiply with. 304 | 305 | @return The result of the operation. 306 | */ 307 | - (Matrix *)matrixByTransposingAndMultiplyingWithLeft:(Matrix *)mt; 308 | 309 | /** 310 | Returns the result of multiplying the receiver with scalar |ms|. 311 | 312 | @param ms The scalar to multiply with. 313 | 314 | @return The result of the multiplication. 315 | */ 316 | - (Matrix *)matrixByMultiplyingWithScalar:(double)ms; 317 | 318 | /** 319 | Returns the result of multiplying the receiver with scalar |ms| and adding matrix |addend|. 320 | 321 | @param ms The scalar to multiply with 322 | @param addend The matrix to add. 323 | 324 | @return The result of the operation. 325 | */ 326 | - (Matrix *)matrixByMultiplyingWithScalar:(double)ms AndAdding:(Matrix *)addend; 327 | 328 | /** 329 | Negates the receiver. 330 | 331 | @return The result of the negation. 332 | */ 333 | - (Matrix *)matrixByNegating; 334 | 335 | /** 336 | Returns a matrix by squaring the elements of the receiver. 337 | 338 | @return The matrix with squared elements. 339 | */ 340 | - (Matrix *)matrixBySquaring; 341 | 342 | /** 343 | Returns a matrix by absolute values of the receiver. 344 | 345 | @return The matrix with the absolute values of the elements. 346 | */ 347 | - (Matrix *)matrixByAbsolute; 348 | 349 | /** 350 | Returns the transpose of the receiver. 351 | 352 | @return The result of the transposition. 353 | */ 354 | - (Matrix *)matrixByTransposing; 355 | 356 | /** 357 | Returns the result of elementwise multiplication of the receiver with matrix |mt|. 358 | 359 | @param mt The matrix to elementwise multiply with. 360 | 361 | @return The result of the elementwise multiplication. 362 | */ 363 | - (Matrix *)matrixByElementWiseMultiplyWith:(Matrix *)mt; 364 | 365 | /** 366 | Returns the result of elementwise division of the receiver by matrix |mt|. 367 | 368 | @param mt The matrix to elementwise divide by. 369 | 370 | @return The result of the elementwise division. 371 | */ 372 | - (Matrix *)matrixByElementWisDivideBy:(Matrix *)mt; 373 | 374 | /// @name In-place Matrix Operations 375 | 376 | /** 377 | Performs an in-place addition of |addend|. 378 | 379 | @param addend The matrix to add. 380 | */ 381 | - (void)add:(Matrix *)addend; 382 | 383 | /** 384 | Performs an in-place subtraction of |subtrahend|. 385 | 386 | @param subtrahend The matrix to subtract. 387 | */ 388 | - (void)subtract:(Matrix *)subtrahend; 389 | 390 | /** 391 | Performs an in-place scalar multiplication of the receiver. 392 | 393 | @param ms The scalar to multiply with. 394 | */ 395 | - (void)multiplyWithScalar:(double)ms; 396 | 397 | /** 398 | Performs an in-place negation of the receiver's elements. 399 | */ 400 | - (void)negate; 401 | 402 | /** 403 | Performs an in-place squaring of the receiver's elements. 404 | */ 405 | - (void)square; 406 | 407 | /** 408 | Performs an in-place absolute of the receiver's elements. 409 | */ 410 | - (void)absolute; 411 | 412 | /** 413 | Returns the result of an elementwise multiplication with matrix |mt|. 414 | 415 | @param mt The result of the elementwise multiplication. 416 | */ 417 | - (void)elementWiseMultiply:(Matrix *)mt; 418 | 419 | /** 420 | Returns the result of an elementwise division by matrix |mt|. 421 | 422 | @param mt The result of the elementwise division. 423 | */ 424 | - (void)elementWiseDivide:(Matrix *)mt; 425 | 426 | /** 427 | Sets all values of the matrix on its diagonal to the specified value 428 | 429 | @param value The value to set the values on the diagonal to. 430 | */ 431 | - (void)setDiagonalTo:(double)value; 432 | 433 | /** 434 | Returns the trace of this matrix. 435 | 436 | @return A double corresponding to the calculated trace of the receiver. 437 | */ 438 | - (double)trace; 439 | 440 | /** 441 | Returns a double resulting from the summation of an elementwise multiplication of the receiver with |other| 442 | 443 | @param other The matrix to perform the elementwise multiplication with. 444 | 445 | @return A double corresponding to the result of the operation. 446 | */ 447 | - (double)dotWith:(Matrix *)other; 448 | 449 | /** 450 | Returns a copy that is normalized to the range [0,1]. 451 | 452 | @return The matrix copy. 453 | @warning This method is applicable only to vectors. 454 | */ 455 | - (Matrix *)matrixByUnitizing; 456 | 457 | /** 458 | Compares the receiver with a matrix, using the specified numerical tolerance 459 | 460 | @param aMatrix The other matrix 461 | @param precision The numerical tolerance used for comparison 462 | 463 | @return Boolean showing whether the matrix objects are equal or not. 464 | */ 465 | - (BOOL)isEqualToMatrix:(Matrix *)aMatrix tolerance:(double)tolerance; 466 | 467 | /** 468 | Returns the data array of the receiver. 469 | */ 470 | @property (readonly) double *array; 471 | 472 | /** 473 | Returns a copy of the data array of thereceiver. 474 | */ 475 | @property (readonly) double *arrayCopy; 476 | 477 | /** 478 | Returns an NSArray with the content of the data array of the receiver. 479 | */ 480 | @property (readonly) NSArray *numberArray; 481 | 482 | /** 483 | Returns a column matrix (vector) containing the elements of the diagonal of the receiver. 484 | 485 | @warning Calling this method repeatedly will incur a performance penalty, 486 | since the elements need to be extracted every time. Better store 487 | the result and reuse. 488 | */ 489 | @property (readonly) Matrix *diagonal; 490 | 491 | /** 492 | Returns the number of rows of the receiver. 493 | */ 494 | @property (readonly) int rows; 495 | 496 | /** 497 | Returns the number of columns of the receiver. 498 | */ 499 | @property (readonly) int columns; 500 | 501 | /** 502 | Returns the length of the data array of the receiver. 503 | */ 504 | @property (readonly) NSUInteger count; 505 | 506 | /** 507 | Returns the sum of all the elements of the receiver. 508 | */ 509 | @property (readonly) double sum; 510 | 511 | /** 512 | Returns the product of all the elements of the receiver. 513 | */ 514 | @property (readonly) double product; 515 | 516 | /** 517 | Returns the smallest value among the elements of the receiver. 518 | */ 519 | @property (readonly) double min; 520 | 521 | /** 522 | Returns the largest value among the elements of the receiver. 523 | */ 524 | @property (readonly) double max; 525 | 526 | /** 527 | Returns YES if the receiver is a square matrix. 528 | */ 529 | @property (readonly) BOOL isSquareMatrix; 530 | 531 | @end 532 | -------------------------------------------------------------------------------- /YCMatrix/Matrix.m: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "Matrix.h" 28 | #import "Constants.h" 29 | 30 | @implementation Matrix 31 | 32 | #pragma mark Factory Methods 33 | 34 | + (instancetype)matrixOfRows:(int)m columns:(int)n 35 | { 36 | return [self matrixOfRows:m columns:n valuesInDiagonal:nil value:0]; 37 | } 38 | 39 | + (instancetype)matrixLike:(Matrix *)other 40 | { 41 | return [self matrixOfRows:other->rows columns:other->columns]; 42 | } 43 | 44 | + (instancetype)onesLike:(Matrix *)other 45 | { 46 | return [self matrixOfRows:other->rows columns:other->columns value:1.0]; 47 | } 48 | 49 | + (instancetype)dirtyMatrixOfRows:(int)m columns:(int)n 50 | { 51 | double *new_m = malloc(m*n * sizeof(double)); 52 | Matrix *mt = [self matrixFromArray:new_m rows:m columns:n mode:YCMWeak]; 53 | mt->freeData = YES; 54 | return mt; 55 | } 56 | 57 | + (instancetype)matrixOfRows:(int)m columns:(int)n value:(double)val 58 | { 59 | return [self matrixOfRows:m columns:n valuesInDiagonal:nil value:val]; 60 | } 61 | 62 | + (instancetype)matrixOfRows:(int)m 63 | columns:(int)n 64 | valueInDiagonal:(double)diagonal 65 | value:(double)val 66 | { 67 | double *new_m = malloc(m*n*sizeof(double)); 68 | Matrix *mt = [self matrixFromArray:new_m rows:m columns:n mode:YCMWeak]; 69 | mt->freeData = YES; 70 | int len = m*n; 71 | 72 | vDSP_vfillD(&val, mt->matrix, 1, len); 73 | 74 | int mind = MIN(m, n); 75 | for (int i=0; imatrix[i*(n+1)] = diagonal; 78 | } 79 | return mt; 80 | } 81 | 82 | + (instancetype)matrixOfRows:(int)m 83 | columns:(int)n 84 | valuesInDiagonal:(double *)diagonal 85 | value:(double)val 86 | { 87 | double *new_m = malloc(m*n*sizeof(double)); 88 | Matrix *mt = [self matrixFromArray:new_m rows:m columns:n mode:YCMWeak]; 89 | mt->freeData = YES; 90 | int len = m*n; 91 | for (int i=0; imatrix[i] = val; 94 | } 95 | if (diagonal) 96 | { 97 | int mind = MIN(m, n); 98 | for (int i=0; imatrix[i*(n+1)] = diagonal[i]; 101 | } 102 | } 103 | return mt; 104 | } 105 | 106 | + (instancetype)matrixFromArray:(double *)arr rows:(int)m columns:(int)n 107 | { 108 | return [self matrixFromArray:arr rows:m columns:n mode:YCMCopy]; 109 | } 110 | 111 | + (instancetype)matrixFromArray:(double *)arr rows:(int)m columns:(int)n mode:(refMode)mode 112 | { 113 | Matrix *mt = [[Matrix alloc] init]; 114 | if (mode == YCMCopy) 115 | { 116 | double *new_m = malloc(m*n*sizeof(double)); 117 | memcpy(new_m, arr, m*n*sizeof(double)); 118 | mt->matrix = new_m; 119 | mt->freeData = YES; 120 | } 121 | else 122 | { 123 | mt->matrix = arr; 124 | mt->freeData = NO; 125 | } 126 | if (mode != YCMWeak) mt->freeData = YES; 127 | mt->rows = m; 128 | mt->columns = n; 129 | return mt; 130 | } 131 | 132 | + (instancetype)matrixFromNSArray:(NSArray *)arr rows:(int)m columns:(int)n 133 | { 134 | if([arr count] != m*n) 135 | @throw [NSException exceptionWithName:@"MatrixSizeException" 136 | reason:@"Matrix size does not match that of the input array." 137 | userInfo:nil]; 138 | Matrix *newMatrix = [Matrix matrixOfRows:m columns:n]; 139 | double *cArray = newMatrix->matrix; 140 | NSUInteger j=[arr count]; 141 | for (int i=0; imatrix rows:other->rows columns:other->columns]; 151 | return mt; 152 | } 153 | 154 | + (instancetype)identityOfRows:(int)m columns:(int)n 155 | { 156 | double *new_m = calloc(m*n, sizeof(double)); 157 | int minsize = m; 158 | if (n < m) minsize = n; 159 | for(int i=0; imatrix, 1, addend->matrix, 1, result->matrix, 1, self.count); 209 | return result; 210 | } 211 | 212 | - (Matrix *)matrixBySubtracting:(Matrix *)subtrahend 213 | { 214 | Matrix *result = [Matrix dirtyMatrixOfRows:self.rows columns:self.columns]; 215 | vDSP_vsubD(subtrahend->matrix, 1, self->matrix, 1, result->matrix, 1, self.count); 216 | return result; 217 | } 218 | 219 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt 220 | { 221 | return [self matrixByTransposing:NO 222 | TransposingRight:NO 223 | MultiplyWithRight:mt 224 | Factor:1 225 | Adding:nil]; 226 | } 227 | 228 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt AndTransposing:(bool)trans 229 | { 230 | Matrix *M1 = trans ? mt : self; 231 | Matrix *M2 = trans ? self : mt; 232 | return [M1 matrixByTransposing:trans 233 | TransposingRight:trans 234 | MultiplyWithRight:M2 235 | Factor:1 236 | Adding:nil]; 237 | } 238 | 239 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt AndAdding:(Matrix *)ma 240 | { 241 | return [self matrixByTransposing:NO 242 | TransposingRight:NO 243 | MultiplyWithRight:mt 244 | Factor:1 245 | Adding:ma]; 246 | } 247 | 248 | - (Matrix *)matrixByMultiplyingWithRight:(Matrix *)mt AndFactor:(double)sf 249 | { 250 | return [self matrixByTransposing:NO 251 | TransposingRight:NO 252 | MultiplyWithRight:mt 253 | Factor:sf 254 | Adding:nil]; 255 | } 256 | 257 | - (Matrix *)matrixByTransposingAndMultiplyingWithRight:(Matrix *)mt 258 | { 259 | return [self matrixByTransposing:YES 260 | TransposingRight:NO 261 | MultiplyWithRight:mt 262 | Factor:1 263 | Adding:nil]; 264 | } 265 | 266 | - (Matrix *)matrixByTransposingAndMultiplyingWithLeft:(Matrix *)mt 267 | { 268 | return [mt matrixByTransposing:NO 269 | TransposingRight:YES 270 | MultiplyWithRight:self 271 | Factor:1 272 | Adding:nil]; 273 | } 274 | 275 | // 276 | // Actual calls to BLAS 277 | 278 | - (Matrix *)matrixByTransposing:(BOOL)transposeLeft 279 | TransposingRight:(BOOL)transposeRight 280 | MultiplyWithRight:(Matrix *)mt 281 | Factor:(double)factor 282 | Adding:(Matrix *)addend 283 | { 284 | int M = transposeLeft ? columns : rows; 285 | int N = transposeRight ? mt->rows : mt->columns; 286 | int K = transposeLeft ? rows : columns; 287 | int lda = columns; 288 | int ldb = mt->columns; 289 | int ldc = N; 290 | 291 | if ((transposeLeft ? rows : columns) != (transposeRight ? mt->columns : mt->rows)) 292 | { 293 | @throw [NSException exceptionWithName:@"MatrixSizeException" 294 | reason:@"Matrix size unsuitable for multiplication." 295 | userInfo:nil]; 296 | } 297 | if (addend && (addend->rows != M && addend->columns != N)) // FIX!!! 298 | { 299 | @throw [NSException exceptionWithName:@"MatrixSizeException" 300 | reason:@"Matrix size unsuitable for addition." 301 | userInfo:nil]; 302 | } 303 | enum CBLAS_TRANSPOSE lT = transposeLeft ? CblasTrans : CblasNoTrans; 304 | enum CBLAS_TRANSPOSE rT = transposeRight ? CblasTrans : CblasNoTrans; 305 | 306 | Matrix *result = addend ?[Matrix matrixFromMatrix:addend] :[Matrix matrixOfRows:M 307 | columns:N]; 308 | cblas_dgemm(CblasRowMajor, lT, rT, M, 309 | N, K, factor, matrix, 310 | lda, mt->matrix, ldb, 1, 311 | result->matrix, ldc); 312 | return result; 313 | } 314 | 315 | - (Matrix *)matrixByMultiplyingWithScalar:(double)ms 316 | { 317 | Matrix *product = [Matrix matrixFromMatrix:self]; 318 | cblas_dscal(rows*columns, ms, product->matrix, 1); 319 | return product; 320 | } 321 | 322 | - (Matrix *)matrixByMultiplyingWithScalar:(double)ms AndAdding:(Matrix *)addend 323 | { 324 | if(columns != addend->columns || rows != addend->rows || sizeof(matrix) != sizeof(addend->matrix)) 325 | @throw [NSException exceptionWithName:@"MatrixSizeException" 326 | reason:@"Matrix size mismatch." 327 | userInfo:nil]; 328 | Matrix *sum = [Matrix matrixFromMatrix:addend]; 329 | cblas_daxpy(rows*columns, ms, self->matrix, 1, sum->matrix, 1); 330 | return sum; 331 | } 332 | 333 | // End of actual calls to BLAS 334 | // 335 | 336 | - (Matrix *)matrixByNegating 337 | { 338 | Matrix *result = [Matrix dirtyMatrixOfRows:self->rows columns:self->columns]; 339 | vDSP_vnegD(self->matrix, 1, result->matrix, 1, self.count); 340 | return result; 341 | } 342 | 343 | - (Matrix *)matrixBySquaring 344 | { 345 | Matrix *result = [Matrix dirtyMatrixOfRows:self->rows columns:self->columns]; 346 | vDSP_vsqD(self->matrix, 1, result->matrix, 1, self.count); 347 | return result; 348 | } 349 | 350 | - (Matrix *)matrixByAbsolute 351 | { 352 | Matrix *result = [Matrix dirtyMatrixOfRows:self->rows columns:self->columns]; 353 | vDSP_vabsD(self->matrix, 1, result->matrix, 1, self.count); 354 | return result; 355 | } 356 | 357 | - (Matrix *)matrixByTransposing 358 | { 359 | Matrix *trans = [Matrix dirtyMatrixOfRows:columns columns:rows]; 360 | vDSP_mtransD(self->matrix, 1, trans->matrix, 1, trans->rows, trans->columns); 361 | return trans; 362 | } 363 | 364 | - (Matrix *)matrixByElementWiseMultiplyWith:(Matrix *)mt 365 | { 366 | Matrix *result = [self copy]; 367 | [result elementWiseMultiply:mt]; 368 | return result; 369 | } 370 | 371 | - (Matrix *)matrixByElementWisDivideBy:(Matrix *)mt 372 | { 373 | Matrix *result = [self copy]; 374 | [result elementWiseDivide:mt]; 375 | return result; 376 | } 377 | 378 | - (void)add:(Matrix *)addend 379 | { 380 | NSAssert(columns == addend->columns && rows == addend->rows, @"Matrix size error"); 381 | vDSP_vaddD(self->matrix, 1, addend->matrix, 1, self->matrix, 1, self.count); 382 | } 383 | 384 | - (void)subtract:(Matrix *)subtrahend 385 | { 386 | NSAssert(columns == subtrahend->columns && rows == subtrahend->rows, @"Matrix size error"); 387 | vDSP_vsubD(subtrahend->matrix, 1, self->matrix, 1, self->matrix, 1, self.count); 388 | } 389 | 390 | - (void)multiplyWithScalar:(double)ms 391 | { 392 | //cblas_dscal(rows*columns, ms, matrix, 1); 393 | vDSP_vsmulD(self->matrix, 1, &ms, self->matrix, 1, self.count); 394 | } 395 | 396 | - (void)negate 397 | { 398 | vDSP_vnegD(self->matrix, 1, self->matrix, 1, self.count); 399 | } 400 | 401 | - (void)square 402 | { 403 | vDSP_vsqD(self->matrix, 1, self->matrix, 1, self.count); 404 | } 405 | 406 | - (void)absolute 407 | { 408 | vDSP_vabsD(self->matrix, 1, self->matrix, 1, self.count); 409 | } 410 | 411 | - (void)elementWiseMultiply:(Matrix *)mt 412 | { 413 | NSAssert(columns == mt->columns && rows == mt->rows, @"Matrix size error"); 414 | for (int i=0, j=self->rows * self->columns; imatrix[i] *= mt->matrix[i]; 417 | } 418 | } 419 | 420 | - (void)elementWiseDivide:(Matrix *)mt 421 | { 422 | NSAssert(columns == mt->columns && rows == mt->rows, @"Matrix size error"); 423 | for (int i=0, j=self->rows * self->columns; imatrix[i] /= mt->matrix[i]; 426 | } 427 | } 428 | 429 | - (void)setDiagonalTo:(double)value 430 | { 431 | for (int i=0, j=MIN(rows, columns); imatrix[i * (columns + 1)] = value; 434 | } 435 | } 436 | 437 | - (double)trace 438 | { 439 | NSAssert(columns == rows, @"Matrix not square"); 440 | double trace = 0; 441 | for (int i=0; irows * self->columns, self->matrix, 1, other->matrix, 1); 453 | } 454 | 455 | - (Matrix *)matrixByUnitizing 456 | { 457 | if(columns != 1 && rows != 1) 458 | @throw [NSException exceptionWithName:@"MatrixSizeException" 459 | reason:@"Unit can only be performed on vectors." 460 | userInfo:nil]; 461 | int len = rows * columns; 462 | double sqsum = 0; 463 | for (int i=0; imatrix; 471 | for (int i=0; irows*self->columns, sizeof(double)); 486 | memcpy(resArr, matrix, self->rows*self->columns*sizeof(double)); 487 | return resArr; 488 | } 489 | 490 | - (NSArray *)numberArray 491 | { 492 | int length = self->rows * self->columns; 493 | NSMutableArray *result = [NSMutableArray arrayWithCapacity:length]; 494 | for (int i=0; imatrix[i])]; 497 | } 498 | return result; 499 | } 500 | 501 | - (Matrix *)diagonal 502 | { 503 | int minDim = MIN(rows, columns); 504 | Matrix *result = [Matrix matrixOfRows:minDim columns:1]; 505 | for (int i=0; irows; 515 | } 516 | 517 | - (int)columns 518 | { 519 | return self->columns; 520 | } 521 | 522 | - (NSUInteger)count 523 | { 524 | return self->rows * self->columns; 525 | } 526 | 527 | - (double)sum 528 | { 529 | double sum = 0; 530 | NSUInteger j= [self count]; 531 | for (int i=0; imatrix[i]; 534 | } 535 | return sum; 536 | } 537 | 538 | - (double)product 539 | { 540 | double product = 1; 541 | NSUInteger j= [self count]; 542 | for (int i=0; imatrix[i]; 545 | } 546 | return product; 547 | } 548 | 549 | - (double)min 550 | { 551 | double min = DBL_MAX; 552 | NSUInteger j= [self count]; 553 | for (int i=0; imatrix[i] < min) min = self->matrix[i]; 556 | } 557 | return min; 558 | } 559 | 560 | - (double)max 561 | { 562 | double max = -DBL_MAX; 563 | NSUInteger j= [self count]; 564 | for (int i=0; imatrix[i] > max) max = self->matrix[i]; 567 | } 568 | return max; 569 | } 570 | 571 | - (BOOL)isSquareMatrix 572 | { 573 | return self->rows == self->columns; 574 | } 575 | 576 | - (BOOL)isEqual:(id)anObject { 577 | if (![anObject isKindOfClass:[self class]]) return NO; 578 | Matrix *other = (Matrix *)anObject; 579 | if (rows != other->rows || columns != other->columns) return NO; 580 | int arr_length = self->rows * self->columns; 581 | for (int i=0; imatrix[i]) return NO; 583 | } 584 | return YES; 585 | } 586 | 587 | - (NSUInteger)hash 588 | { 589 | // An implementation of 590 | // http://www.cse.yorku.ca/~oz/hash.html 591 | unsigned long hash = 5381; 592 | int c; 593 | char ch[10]; 594 | 595 | for (int i=0, k=(int)self.count; imatrix[i]; 598 | sprintf(ch , "%lf" , d); 599 | c = 0; 600 | 601 | for (int j=0; j<8; j++) 602 | { 603 | c = ch[j] - '0'; 604 | hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 605 | } 606 | } 607 | hash = ((hash << 5) + hash) + self.rows; 608 | hash = ((hash << 5) + hash) + self.columns; 609 | 610 | return hash; 611 | } 612 | 613 | - (BOOL)isEqualToMatrix:(Matrix *)aMatrix tolerance:(double)tolerance 614 | { 615 | if (self->rows != aMatrix->rows || self->columns != aMatrix->columns) return NO; 616 | int arr_length = self->rows * self->columns; 617 | for (int i=0; imatrix[i]); 620 | if ( diff > tolerance ) return NO; 621 | } 622 | return YES; 623 | } 624 | 625 | - (NSString *)description { 626 | NSString *s = @"\n"; 627 | for ( int i=0; ifreeData) free(self->matrix); 638 | } 639 | 640 | #pragma mark NSCoding Implementation 641 | 642 | - (void)encodeWithCoder:(NSCoder *)encoder 643 | { 644 | [encoder encodeBytes:(const uint8_t *)self->matrix 645 | length:self.count * sizeof(double) 646 | forKey:@"matrix"]; 647 | [encoder encodeInt:self->rows forKey:@"rows"]; 648 | [encoder encodeInt:self->columns forKey:@"columns"]; 649 | } 650 | 651 | - (instancetype)initWithCoder:(NSCoder *)decoder 652 | { 653 | if (self = [super init]) 654 | { 655 | self->freeData = YES; 656 | self->rows = [decoder decodeIntForKey:@"rows"]; 657 | self->columns = [decoder decodeIntForKey:@"columns"]; 658 | if ([decoder containsValueForKey:@"matrix"]) 659 | { 660 | NSUInteger length; 661 | double *tempMatrix = (double *)[decoder decodeBytesForKey:@"matrix" returnedLength:&length]; 662 | NSAssert(length == self.count * sizeof(double), @"Decoded matrix length differs"); 663 | self->matrix = malloc(length); 664 | memcpy(self->matrix, tempMatrix, length); 665 | } 666 | else 667 | { 668 | // legacy decoding 669 | NSArray *matrixContent = [decoder decodeObjectForKey:@"matrixContent"]; 670 | int len = self->rows*self->columns; 671 | self->matrix = malloc(len*sizeof(double)); 672 | for (int i=0; imatrix[i] = [matrixContent[i] doubleValue]; 675 | } 676 | } 677 | } 678 | return self; 679 | } 680 | 681 | - (instancetype)copyWithZone:(NSZone *)zone 682 | { 683 | Matrix *newMatrix = [Matrix matrixFromArray:self->matrix 684 | rows:self->rows 685 | columns:self->columns]; 686 | return newMatrix; 687 | } 688 | 689 | @end 690 | -------------------------------------------------------------------------------- /YCMatrix/NSArray+Matrix.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Matrix.h 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import "Matrix.h" 29 | 30 | @interface NSArray (Matrix) 31 | 32 | /** 33 | Returns a matrix that contains the sum of all matrices 34 | contained in the receiver. 35 | */ 36 | @property (readonly) Matrix *matrixSum; 37 | 38 | /** 39 | Returna a matrix that contains the element-wise product of 40 | all matrices contained in the receiver. 41 | */ 42 | @property (readonly) Matrix *matrixProduct; 43 | 44 | /** 45 | Returns a matrix that contains the element-wise mean values of 46 | all matrices contained in the receiver. 47 | */ 48 | @property (readonly) Matrix *matrixMean; 49 | 50 | /** 51 | Returns a matrix that contains the element-wise maximum values of 52 | all matrices contained in the receiver. 53 | */ 54 | @property (readonly) Matrix *matrixMax; 55 | 56 | /** 57 | Returns a matrix that contains the element-wise minimum values of 58 | all matrices contained in the receiver. 59 | */ 60 | @property (readonly) Matrix *matrixMin; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /YCMatrix/NSArray+Matrix.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Matrix.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "NSArray+Matrix.h" 28 | 29 | @implementation NSArray (Matrix) 30 | 31 | - (Matrix *)matrixSum 32 | { 33 | Matrix *result; 34 | for (Matrix *m in self) 35 | { 36 | NSAssert([m isKindOfClass:[Matrix class]], @"Array element is not a matrix"); 37 | if (!result) 38 | { 39 | result = [m copy]; 40 | } 41 | else 42 | { 43 | [result add:m]; 44 | } 45 | } 46 | return result; 47 | } 48 | 49 | - (Matrix *)matrixMean 50 | { 51 | Matrix *result = [self matrixSum]; 52 | [result multiplyWithScalar:1.0 / (double)self.count]; 53 | return result; 54 | } 55 | 56 | - (Matrix *)matrixProduct 57 | { 58 | Matrix *result; 59 | for (Matrix *m in self) 60 | { 61 | NSAssert([m isKindOfClass:[Matrix class]], @"Array element is not a matrix"); 62 | if (!result) 63 | { 64 | result = [m copy]; 65 | } 66 | else 67 | { 68 | [result elementWiseMultiply:m]; 69 | } 70 | } 71 | return result; 72 | } 73 | 74 | - (Matrix *)matrixMax 75 | { 76 | Matrix *result; 77 | for (Matrix *m in self) 78 | { 79 | NSAssert([m isKindOfClass:[Matrix class]], @"Array element is not a matrix"); 80 | if (!result) 81 | { 82 | result = [m copy]; 83 | } 84 | else 85 | { 86 | for (int i=0, n=(int)result.count; i 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 0.6.16 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Copyright © 2013 - 2016 Ioannis Chatzikonstantinou. All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /YCMatrix/YCMatrix.h: -------------------------------------------------------------------------------- 1 | // 2 | // YCMatrix.h 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | #import "Matrix+Advanced.h" 30 | #import "Matrix+Manipulate.h" 31 | #import "Matrix+Map.h" 32 | #import "NSArray+Matrix.h" -------------------------------------------------------------------------------- /YCMatrix/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /YCMatrixTests/YCMatrixAdvancedTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // YCMatrixAdvancedTests.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | @import XCTest; 28 | @import YCMatrix; 29 | #import 30 | 31 | #define ARC4RANDOM_MAX 0x100000000 32 | 33 | // Definitions for convenience logging functions (without date/object and title logging). 34 | #define CleanNSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 35 | #define TitleNSLog(FORMAT, ...) fprintf(stderr,"\n%s\n_____________________________________\n\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 36 | 37 | @interface YCMatrixAdvancedTests : XCTestCase 38 | 39 | @end 40 | 41 | @implementation YCMatrixAdvancedTests 42 | 43 | - (void)testUniformRandom 44 | { 45 | Matrix *lower = [Matrix matrixFromNSArray:@[@10, @5, @5, @10] rows:1 columns:4]; 46 | Matrix *upper = [Matrix matrixFromNSArray:@[@20, @6, @10, @30] rows:1 columns:4]; 47 | Matrix *random = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 48 | CleanNSLog(@"%@", random); 49 | XCTAssert([random i:0 j:0]>10); 50 | XCTAssert([random i:0 j:0]<20); 51 | XCTAssert([random i:0 j:1]>5); 52 | XCTAssert([random i:0 j:1]<6); 53 | XCTAssert([random i:0 j:2]>5); 54 | XCTAssert([random i:0 j:2]<10); 55 | XCTAssert([random i:0 j:3]>10); 56 | XCTAssert([random i:0 j:3]<30); 57 | } 58 | 59 | - (void)testNormalRandomColumns 60 | { 61 | Matrix *mean = [Matrix matrixFromNSArray:@[@10, @5, @5, @10] rows:1 columns:4]; 62 | Matrix *variance = [Matrix matrixFromNSArray:@[@1, @2, @3, @4] rows:1 columns:4]; 63 | Matrix *random = [Matrix normalRandomMean:mean variance:variance count:20000]; 64 | Matrix *actualMean = [random meansOfColumns]; 65 | Matrix *actualVariance = [random variancesOfColumns]; 66 | 67 | XCTAssert([mean isEqualToMatrix:actualMean tolerance:0.1]); 68 | XCTAssert([variance isEqualToMatrix:actualVariance tolerance:0.1]); 69 | } 70 | 71 | - (void)testNormalRandomRows 72 | { 73 | Matrix *mean = [Matrix matrixFromNSArray:@[@10, @5, @5, @10] rows:4 columns:1]; 74 | Matrix *variance = [Matrix matrixFromNSArray:@[@1, @2, @3, @4] rows:4 columns:1]; 75 | Matrix *random = [Matrix normalRandomMean:mean variance:variance count:20000]; 76 | Matrix *actualMean = [random meansOfRows]; 77 | Matrix *actualVariance = [random variancesOfRows]; 78 | 79 | XCTAssert([mean isEqualToMatrix:actualMean tolerance:0.1]); 80 | XCTAssert([variance isEqualToMatrix:actualVariance tolerance:0.1]); 81 | } 82 | 83 | - (void)testSVD 84 | { 85 | TitleNSLog(@"Singular Value Decomposition"); 86 | int m = 10; 87 | int n = 6; 88 | double *orig_array = _mm_malloc(m*n*sizeof(double), 64); 89 | for (int i=0, j=m*n; irows, po->columns); 110 | CleanNSLog(@"%@",po); 111 | CleanNSLog(@"PseudoInverse: %ix%i",poi->rows, poi->columns); 112 | CleanNSLog(@"%@",poi); 113 | 114 | double pinv_orig_array2[6] = { 1.0, 2.0, 115 | 3.0, 4.0, 5.0, 6.0}; 116 | Matrix *po2 = [Matrix matrixFromArray:pinv_orig_array2 rows:3 columns:2]; 117 | Matrix *poi2 = [po2 pseudoInverse]; 118 | CleanNSLog(@"Original: %ix%i",po2->rows, po2->columns); 119 | CleanNSLog(@"%@",po2); 120 | CleanNSLog(@"PseudoInverse: %ix%i",poi2->rows, poi2->columns); 121 | CleanNSLog(@"%@",poi2); 122 | } 123 | 124 | - (void)testCholesky 125 | { 126 | TitleNSLog(@"Cholesky Decomposition Test (A: 3x3)"); 127 | double simple_array[9] = { 4, 12, -16, 128 | 12, 37, -43, 129 | -16, -43, 98}; // Test from Wikipedia 130 | Matrix *A = [Matrix matrixFromArray:simple_array rows:3 columns:3]; 131 | CleanNSLog(@"Original Matrix A: %@",A); 132 | Matrix *ch = [A matrixByCholesky]; 133 | CleanNSLog(@"Cholesky Decomposition of A: %@",ch); 134 | XCTAssertEqualObjects([ch matrixByTransposingAndMultiplyingWithLeft:ch], A, 135 | @"Error with Cholesky decomposition"); 136 | 137 | TitleNSLog(@"Cholesky Decomposition Test (Correlation Matrix: 4x4)"); 138 | 139 | double correlation_array[16] = { 1, 0.5, 0.5, 0.5, 140 | 0.5, 1, 0.5, 0.5, 141 | 0.5, 0.5, 1, 0.5, 142 | 0.5, 0.5, 0.5, 1 }; 143 | Matrix *correlationMatrix = [Matrix matrixFromArray:correlation_array rows:4 columns:4]; 144 | 145 | CleanNSLog(@"Correlation Matrix: %@",correlationMatrix); 146 | Matrix *correlationCholesky = [correlationMatrix matrixByCholesky]; 147 | CleanNSLog(@"Cholesky Decomposition of Correlation Matrix: %@",correlationCholesky); 148 | Matrix *response = [correlationCholesky matrixByTransposingAndMultiplyingWithLeft:correlationCholesky]; 149 | XCTAssert([response isEqualToMatrix:correlationMatrix tolerance:1E-9], 150 | @"Error with Cholesky decomposition"); 151 | } 152 | 153 | - (void)testSobol 154 | { 155 | // test integrand from Joe and Kuo paper ... integrates to 1 156 | 157 | int count = 1000; 158 | 159 | TitleNSLog(@"Sobol Sequence Test"); 160 | 161 | Matrix *lower = [Matrix matrixOfRows:10 columns:1 value:0.0]; 162 | Matrix *upper = [Matrix matrixOfRows:10 columns:1 value:1.0]; 163 | 164 | Matrix *sequence = [Matrix sobolSequenceLowerBound:lower upperBound:upper count:count]; 165 | 166 | NSArray *columns = [sequence columnsAsNSArray]; 167 | 168 | double acc = 0; 169 | 170 | for (Matrix *column in columns) 171 | { 172 | double f = 1; 173 | for (int j = 1; j <= column.count; ++j) { 174 | double cj = pow((double) j, 0.3333333333333333333); 175 | f *= (fabs(4*column->matrix[j-1] - 2) + cj) / (1 + cj); 176 | } 177 | acc += f; 178 | } 179 | acc /= count; 180 | 181 | XCTAssertEqualWithAccuracy(acc, 1.0, 0.01); 182 | CleanNSLog(@"%f", acc); 183 | } 184 | 185 | - (void)testHalton 186 | { 187 | // test integrand from Joe and Kuo paper ... integrates to 1 188 | 189 | int count = 1000; 190 | 191 | TitleNSLog(@"Halton Sequence Test"); 192 | 193 | Matrix *lower = [Matrix matrixOfRows:10 columns:1 value:0.0]; 194 | Matrix *upper = [Matrix matrixOfRows:10 columns:1 value:1.0]; 195 | 196 | Matrix *sequence = [Matrix haltonSequenceWithLowerBound:lower upperBound:upper count:count]; 197 | 198 | NSArray *columns = [sequence columnsAsNSArray]; 199 | 200 | double acc = 0; 201 | 202 | for (Matrix *column in columns) 203 | { 204 | double f = 1; 205 | for (int j = 1; j <= column.count; ++j) { 206 | double cj = pow((double) j, 0.3333333333333333333); 207 | f *= (fabs(4*column->matrix[j-1] - 2) + cj) / (1 + cj); 208 | } 209 | acc += f; 210 | } 211 | acc /= count; 212 | 213 | XCTAssertEqualWithAccuracy(acc, 1.0, 0.01); 214 | CleanNSLog(@"%f", acc); 215 | } 216 | 217 | - (void)testMeans 218 | { 219 | TitleNSLog(@"Mean Test"); 220 | double mean_array[12] = { 1.0, 1.0, 1.0, 221 | 4.0, -4.0, 2.0, 222 | -153.0, 614.0, 33.0, 223 | -100.0, 100.0, 0.0}; 224 | double columnMeanTargetArray[3] = { -62.0, 177.75, 9.0 }; 225 | double rowMeantargetArray[4] = { 1.0, 2.0/3.0, 494.0/3.0, 0.0 }; 226 | Matrix *columnMeanTargetMatrix = [Matrix matrixFromArray:columnMeanTargetArray rows:1 columns:3]; 227 | Matrix *rowMeanTargetMatrix = [Matrix matrixFromArray:rowMeantargetArray rows:4 columns:1]; 228 | Matrix *meanMatrix = [Matrix matrixFromArray:mean_array rows:4 columns:3]; 229 | Matrix *rowMeans = [meanMatrix meansOfRows]; 230 | Matrix *columnMeans = [meanMatrix meansOfColumns]; 231 | XCTAssertEqualObjects(rowMeans, rowMeanTargetMatrix, 232 | @"Error in calculating Row Means."); 233 | XCTAssertEqualObjects(columnMeans, columnMeanTargetMatrix, 234 | @"Error in calculating Column Means."); 235 | CleanNSLog(@"%@", rowMeans); 236 | CleanNSLog(@"%@", columnMeans); 237 | } 238 | 239 | - (void)testVariances 240 | { 241 | TitleNSLog(@"Variances Test"); 242 | double var_array[12] = { 1.0, 10.0, 1.0, 243 | 2.0, -6.0, -5.0, 244 | -153.0, 34.0, 15.67, 245 | -110.1, 1900.0, 0.0}; 246 | double columnVarTargetArray[3] = { 6207.66917, 890777.00000, 79.16722 }; 247 | double rowVartargetArray[4] = { 27.00, 19.00, 10625.76, 1277104.00 }; 248 | Matrix *columnVarTargetMatrix = [Matrix matrixFromArray:columnVarTargetArray rows:1 columns:3]; 249 | Matrix *rowVarTargetMatrix = [Matrix matrixFromArray:rowVartargetArray rows:4 columns:1]; 250 | Matrix *varMatrix = [Matrix matrixFromArray:var_array rows:4 columns:3]; 251 | Matrix *rowVars = [varMatrix sampleVariancesOfRows]; 252 | Matrix *columnVars = [varMatrix sampleVariancesOfColumns]; 253 | XCTAssert([rowVars isEqualToMatrix:rowVarTargetMatrix tolerance:0.01], 254 | @"Error in calculating Row Variances."); 255 | XCTAssert([columnVars isEqualToMatrix:columnVarTargetMatrix tolerance:0.01], 256 | @"Error in calculating Column Variances."); 257 | CleanNSLog(@"%@", rowVarTargetMatrix); 258 | CleanNSLog(@"%@", columnVarTargetMatrix); 259 | CleanNSLog(@"%@", rowVars); 260 | CleanNSLog(@"%@", columnVars); 261 | } 262 | 263 | - (void)testMins 264 | { 265 | TitleNSLog(@"Minimums Test"); 266 | double var_array[12] = { 1.0, 10.0, 1.0, 267 | 2.0, -6.0, -5.0, 268 | -153.0, 34.0, 15.67, 269 | -110.1, 1900.0, 0.0}; 270 | double columnMinTargetArray[3] = { -153.0, -6.0, -5.0 }; 271 | double rowMintargetArray[4] = { 1.0, -6.0, -153.0, -110.1 }; 272 | Matrix *columnMinTargetMatrix = [Matrix matrixFromArray:columnMinTargetArray rows:1 columns:3]; 273 | Matrix *rowMinTargetMatrix = [Matrix matrixFromArray:rowMintargetArray rows:4 columns:1]; 274 | Matrix *minMatrix = [Matrix matrixFromArray:var_array rows:4 columns:3]; 275 | Matrix *rowMins = [minMatrix minimumsOfRows]; 276 | Matrix *columnMins = [minMatrix minimumsOfColumns]; 277 | XCTAssert([rowMins isEqualToMatrix:rowMinTargetMatrix tolerance:0.01], 278 | @"Error in calculating Row Minimums."); 279 | XCTAssert([columnMins isEqualToMatrix:columnMinTargetMatrix tolerance:0.01], 280 | @"Error in calculating Column Minimums."); 281 | CleanNSLog(@"%@", rowMinTargetMatrix); 282 | CleanNSLog(@"%@", columnMinTargetMatrix); 283 | CleanNSLog(@"%@", rowMins); 284 | CleanNSLog(@"%@", columnMins); 285 | } 286 | 287 | 288 | - (void)testMaxs 289 | { 290 | TitleNSLog(@"Maximums Test"); 291 | double var_array[12] = { 1.0, 10.0, -1.0, 292 | 2.0, -6.0, -5.0, 293 | -153.0, 34.0, -15.67, 294 | -110.1, 1900.0, -0.1}; 295 | double columnMaxTargetArray[3] = { 2.0, 1900.0, -0.1 }; 296 | double rowMaxTargetArray[4] = { 10.0, 2.00, 34.0, 1900.00 }; 297 | Matrix *columnMaxTargetMatrix = [Matrix matrixFromArray:columnMaxTargetArray rows:1 columns:3]; 298 | Matrix *rowMaxTargetMatrix = [Matrix matrixFromArray:rowMaxTargetArray rows:4 columns:1]; 299 | Matrix *maxMatrix = [Matrix matrixFromArray:var_array rows:4 columns:3]; 300 | Matrix *rowMaxs = [maxMatrix maximumsOfRows]; 301 | Matrix *columnMaxs = [maxMatrix maximumsOfColumns]; 302 | XCTAssert([rowMaxs isEqualToMatrix:rowMaxTargetMatrix tolerance:0.01], 303 | @"Error in calculating Row Maximums."); 304 | XCTAssert([columnMaxs isEqualToMatrix:columnMaxTargetMatrix tolerance:0.01], 305 | @"Error in calculating Column Maximums."); 306 | CleanNSLog(@"%@", rowMaxTargetMatrix); 307 | CleanNSLog(@"%@", columnMaxTargetMatrix); 308 | CleanNSLog(@"%@", rowMaxs); 309 | CleanNSLog(@"%@", columnMaxs); 310 | } 311 | 312 | - (void)testEigenvalues 313 | { 314 | TitleNSLog(@"Eigenvalues Test"); 315 | double simple_array[9] = { 1.000, 2.000, 3.000, 316 | 5.000, 10.000, 15.000, 317 | 0.100, 0.200, 0.300 }; 318 | double ref_array[3] = {11.3, 0.0, 0.0}; 319 | Matrix *original = [Matrix matrixFromArray:simple_array rows:3 columns:3]; 320 | Matrix *ev = [original realEigenvalues]; 321 | Matrix *evRef = [Matrix matrixFromArray:ref_array rows:1 columns:3]; 322 | CleanNSLog(@"%@", ev); 323 | XCTAssert([ev isEqualToMatrix:evRef tolerance:1E-4], @"Error with Eigenvalue calculation"); 324 | } 325 | 326 | - (void)testEigenValuesandVectors 327 | { 328 | TitleNSLog(@"Eigenvectors Test"); 329 | double simple_array[9] = { 35.000, 100.000, 42.000, 330 | 87.000, 72.000, 97.000, 331 | 28.000, 21.000, 55.000 }; 332 | double left_result[9] = {-0.6062, -0.8280, -0.6705, 333 | -0.7489, 0.5461, -0.2132, 334 | -0.2678, 0.1268, 0.7106}; 335 | Matrix *original = [Matrix matrixFromArray:simple_array rows:3 columns:3]; 336 | Matrix *rightTarget = [Matrix matrixFromArray:left_result rows:3 columns:3]; 337 | NSDictionary *e = [original eigenvectorsAndEigenvalues]; 338 | XCTAssert([e[@"Right Eigenvectors"] 339 | isEqualToMatrix:rightTarget tolerance:1E-3]); 340 | } 341 | 342 | - (void)testDeterminant 343 | { 344 | TitleNSLog(@"Determinant Test"); 345 | double simple_array[16] = { 1.0, 2.0, 3.0, 4.0, 346 | 5.0, 6.0, 7.0, 8.0, 347 | 2.0, 6.0, 4.0, 8.0, 348 | 3.0, 1.0, 1.0, 2.0 }; 349 | Matrix *original = [Matrix matrixFromArray:simple_array rows:4 columns:4]; 350 | double det = [original determinant]; 351 | double detRef = 72; 352 | CleanNSLog(@"%f", det); 353 | XCTAssertEqual(det, detRef, @"Error with Determinant calculation"); 354 | } 355 | 356 | - (void)testBernoulli 357 | { 358 | TitleNSLog(@"Bernoulli Distribution Test"); 359 | 360 | Matrix *ones = [Matrix matrixOfRows:20 columns:20 value:1]; 361 | Matrix *onesWithProbability = [ones copy]; 362 | [onesWithProbability bernoulli]; 363 | XCTAssertEqualObjects(ones, onesWithProbability); 364 | 365 | Matrix *zeroes = [Matrix matrixOfRows:20 columns:20 value:0]; 366 | Matrix *zeroesWithProbability = [zeroes copy]; 367 | [zeroesWithProbability bernoulli]; 368 | XCTAssertEqualObjects(zeroes, zeroesWithProbability); 369 | } 370 | 371 | 372 | @end 373 | -------------------------------------------------------------------------------- /YCMatrixTests/YCMatrixManipulateTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ManipulateTests.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | @import XCTest; 28 | @import YCMatrix; 29 | 30 | #define ARC4RANDOM_MAX 0x100000000 31 | 32 | // Definitions for convenience logging functions (without date/object and title logging). 33 | #define CleanNSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 34 | #define TitleNSLog(FORMAT, ...) fprintf(stderr,"\n%s\n_____________________________________\n\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 35 | 36 | @interface YCMatrixManipulateTests : XCTestCase 37 | 38 | @end 39 | 40 | @implementation YCMatrixManipulateTests 41 | 42 | - (void)testRowRetrieval 43 | { 44 | TitleNSLog(@"Matrix row retrieval"); 45 | double testmrarr[6] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; 46 | Matrix *testmr = [Matrix matrixFromArray:testmrarr rows:2 columns:3]; 47 | Matrix *rowm = [testmr row:1]; // This is being tested. 48 | CleanNSLog(@"%@", rowm); 49 | double templatermatrixarr[3] = { 4.0, 5.0, 6.0 }; 50 | Matrix *templatemr = [Matrix matrixFromArray:templatermatrixarr rows:1 columns:3]; 51 | XCTAssertTrue([rowm isEqual:templatemr], @"Matrix row retrieval error."); 52 | } 53 | 54 | - (void)testRowReference 55 | { 56 | TitleNSLog(@"Matrix row referencing"); 57 | double testmrarr[6] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; 58 | Matrix *testmr = [Matrix matrixFromArray:testmrarr rows:2 columns:3]; 59 | Matrix *rowm = [testmr rowReference:1]; // This is being tested. 60 | CleanNSLog(@"%@", rowm); 61 | double templatermatrixarr[3] = { 4.0, 5.0, 6.0 }; 62 | Matrix *templatemr = [Matrix matrixFromArray:templatermatrixarr rows:1 columns:3]; 63 | XCTAssertTrue([rowm isEqual:templatemr], @"Matrix row retrieval error."); 64 | } 65 | 66 | - (void)testRowVectorReference 67 | { 68 | TitleNSLog(@"Matrix row referencing vector"); 69 | double testmrarr[6] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; 70 | Matrix *testmr = [Matrix matrixFromArray:testmrarr rows:2 columns:3]; 71 | Matrix *rowm = [testmr rowReferenceVector:1]; // This is being tested. 72 | CleanNSLog(@"%@", rowm); 73 | double templatermatrixarr[3] = { 4.0, 5.0, 6.0 }; 74 | Matrix *templatemr = [Matrix matrixFromArray:templatermatrixarr rows:3 columns:1]; 75 | XCTAssertTrue([rowm isEqual:templatemr], @"Matrix row retrieval error."); 76 | } 77 | 78 | - (void)testMultiplyRowReference 79 | { 80 | Matrix *source = [Matrix matrixFromNSArray:@[@21.600, 81 | @15.000, 82 | @1.700, 83 | @3.000, 84 | @44.000, 85 | @12.000, 86 | @69.000] rows:1 columns:7]; 87 | Matrix *row = [source rowReference:0]; 88 | row->rows = row->columns; 89 | row->columns = 1; 90 | 91 | Matrix *result = [row matrixByTransposingAndMultiplyingWithRight:row]; 92 | XCTAssertEqual(result.rows, 1); 93 | XCTAssertEqual(result.columns, 1); 94 | double val = [result i:0 j:0]; 95 | XCTAssertEqual(val, 7544.450); 96 | } 97 | 98 | - (void)testMultipleRowRetrieval 99 | { 100 | TitleNSLog(@"Multiple matrix row retrieval"); 101 | double testmrarr[9] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; 102 | Matrix *testmr = [Matrix matrixFromArray:testmrarr rows:3 columns:3]; 103 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 2)]; 104 | Matrix *rowm = [testmr rows:indexSet]; // This is being tested. 105 | CleanNSLog(@"%@", rowm); 106 | double templatermatrixarr[6] = { 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; 107 | Matrix *templatemr = [Matrix matrixFromArray:templatermatrixarr rows:2 columns:3]; 108 | XCTAssertTrue([rowm isEqual:templatemr], @"Multiple matrix row retrieval error."); 109 | } 110 | 111 | - (void)testColumnRetrieval 112 | { 113 | TitleNSLog(@"Matrix column retrieval"); 114 | double testmcarr[6] = { 1.0, 4.0, 2.0, 5.0, 3.0, 6.0 }; 115 | Matrix *testmc = [Matrix matrixFromArray:testmcarr rows:3 columns:2]; 116 | Matrix *columnm = [testmc column:1]; // This is being tested. 117 | CleanNSLog(@"%@", columnm); 118 | double templatecmatrixarr[3] = { 4.0, 5.0, 6.0 }; 119 | Matrix *templatemc = [Matrix matrixFromArray:templatecmatrixarr rows:3 columns:1]; 120 | XCTAssertTrue([columnm isEqual:templatemc], @"Matrix column retrieval error."); 121 | } 122 | 123 | - (void)testMultipleColumnRetrieval 124 | { 125 | TitleNSLog(@"Multiple matrix column retrieval"); 126 | double testmcarr[9] = { 1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0 }; 127 | Matrix *testmc = [Matrix matrixFromArray:testmcarr rows:3 columns:3]; 128 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 2)]; 129 | Matrix *columnm = [testmc columns:indexSet]; // This is being tested. 130 | CleanNSLog(@"%@", columnm); 131 | double templatecmatrixarr[6] = { 4.0, 7.0, 5.0, 8.0, 6.0, 9.0 }; 132 | Matrix *templatemc = [Matrix matrixFromArray:templatecmatrixarr rows:3 columns:2]; 133 | XCTAssertTrue([columnm isEqual:templatemc], @"Multiple matrix column retrieval error."); 134 | } 135 | 136 | - (void)testRowsToNSArray 137 | { 138 | TitleNSLog(@"Rows as NSArray"); 139 | double rowsColumnsArrayTest[12] = { 1.0, 2.0, 3.0, 4.0, 140 | 5.0, 6.0, 7.0, 8.0, 141 | 9.0, 10.0, 11.0, 12.0}; 142 | double firstRow[4] = { 1.0, 2.0, 3.0, 4.0 }; 143 | Matrix *firstRowMatrix = [Matrix matrixFromArray:firstRow rows:1 columns:4]; 144 | double secondRow[4] = { 5.0, 6.0, 7.0, 8.0 }; 145 | Matrix *secondRowMatrix = [Matrix matrixFromArray:secondRow rows:1 columns:4]; 146 | double thirdRow[4] = { 9.0, 10.0, 11.0, 12.0 }; 147 | Matrix *thirdRowMatrix = [Matrix matrixFromArray:thirdRow rows:1 columns:4]; 148 | 149 | Matrix *rowsColumnsTestMatrix = [Matrix matrixFromArray:rowsColumnsArrayTest rows:3 columns:4]; 150 | NSArray *rowsTestRows = [rowsColumnsTestMatrix rowsAsNSArray]; 151 | XCTAssertEqualObjects([rowsTestRows objectAtIndex:0], firstRowMatrix, @"Error in conversion to rows array(1)."); 152 | XCTAssertEqualObjects([rowsTestRows objectAtIndex:1], secondRowMatrix, @"Error in conversion to rows array(2)."); 153 | XCTAssertEqualObjects([rowsTestRows objectAtIndex:2], thirdRowMatrix, @"Error in conversion to rows array(3)."); 154 | } 155 | 156 | // All code under test must be linked into the Unit Test bundle 157 | - (void)testColumnsToNSArray 158 | { 159 | TitleNSLog(@"Columns as NSArray"); 160 | double rowsColumnsArrayTest[12] = { 1.0, 2.0, 3.0, 4.0, 161 | 5.0, 6.0, 7.0, 8.0, 162 | 9.0, 10.0, 11.0, 12.0}; 163 | double firstColumn[3] = { 1.0, 5.0, 9.0 }; 164 | Matrix *firstColumnMatrix = [Matrix matrixFromArray:firstColumn rows:3 columns:1]; 165 | double secondColumn[3] = { 2.0, 6.0, 10.0 }; 166 | Matrix *secondColumnMatrix = [Matrix matrixFromArray:secondColumn rows:3 columns:1]; 167 | double thirdColumn[3] = { 3.0, 7.0, 11.0 }; 168 | Matrix *thirdColumnMatrix = [Matrix matrixFromArray:thirdColumn rows:3 columns:1]; 169 | double fourthColumn[3] = { 4.0, 8.0, 12.0 }; 170 | Matrix *fourthColumnMatrix = [Matrix matrixFromArray:fourthColumn rows:3 columns:1]; 171 | 172 | Matrix *rowsColumnsTestMatrix = [Matrix matrixFromArray:rowsColumnsArrayTest rows:3 columns:4]; 173 | NSArray *columnsTestColumns = [rowsColumnsTestMatrix columnsAsNSArray]; 174 | XCTAssertEqualObjects([columnsTestColumns objectAtIndex:0], firstColumnMatrix, 175 | @"Error in conversion to columns array(1)."); 176 | XCTAssertEqualObjects([columnsTestColumns objectAtIndex:1], secondColumnMatrix, 177 | @"Error in conversion to columns array(2)."); 178 | XCTAssertEqualObjects([columnsTestColumns objectAtIndex:2], thirdColumnMatrix, 179 | @"Error in conversion to columns array(3)."); 180 | XCTAssertEqualObjects([columnsTestColumns objectAtIndex:3], fourthColumnMatrix, 181 | @"Error in conversion to columns array(4)."); 182 | } 183 | 184 | - (void)testSubMatrices 185 | { 186 | TitleNSLog(@"Sub-Matrix Extraction Test"); 187 | double simple_array[16] = { 1.0, 2.0, 3.0, 4.0, 188 | 5.0, 6.0, 7.0, 8.0, 189 | 9.0, 10.0, 11.0, 12.0, 190 | 13.0, 14.0, 15.0, 16.0 }; 191 | Matrix *original = [Matrix matrixFromArray:simple_array rows:4 columns:4]; 192 | 193 | double expected_rows[8] = { 5.0, 6.0, 7.0, 8.0, 194 | 9.0, 10.0, 11.0, 12.0 }; 195 | Matrix *expectedRows = [Matrix matrixFromArray:expected_rows rows:2 columns:4]; 196 | Matrix *resultRows = [original matrixWithRowsInRange:NSMakeRange(1, 2)]; 197 | CleanNSLog(@"%@", resultRows); 198 | XCTAssertEqualObjects(expectedRows, resultRows, @"Error while extracting rows to sub-matrix"); 199 | 200 | double expected_columns[8] = { 2.0, 3.0, 201 | 6.0, 7.0, 202 | 10.0, 11.0, 203 | 14.0, 15.0 }; 204 | Matrix *expectedColumns = [Matrix matrixFromArray:expected_columns rows:4 columns:2]; 205 | Matrix *resultColumns = [original matrixWithColumnsInRange:NSMakeRange(1, 2)]; 206 | CleanNSLog(@"%@", resultColumns); 207 | XCTAssertEqualObjects(expectedColumns, resultColumns, @"Error while extracting columns to sub-matrix"); 208 | } 209 | 210 | - (void)testRowAndColumnAdditionsSubtractions 211 | { 212 | TitleNSLog(@"Row / Column Additions / Subtractions"); 213 | double simple_array[16] = { 1.0, 2.0, 3.0, 4.0, 214 | 5.0, 6.0, 7.0, 8.0, 215 | 9.0, 10.0, 11.0, 12.0, 216 | 13.0, 14.0, 15.0, 16.0 }; 217 | Matrix *original = [Matrix matrixFromArray:simple_array rows:4 columns:4]; 218 | double element[4] = { 4.0, 1.0, -40.0, -22.5 }; 219 | Matrix *column = [Matrix matrixFromArray:element rows:4 columns:1]; 220 | Matrix *row = [Matrix matrixFromArray:element rows:1 columns:4]; 221 | Matrix *step1 = [original matrixByAddingRow:row]; 222 | Matrix *step2 = [step1 matrixByAddingColumn:column]; 223 | Matrix *step3 = [step2 matrixBySubtractingColumn:column]; 224 | Matrix *step4 = [step3 matrixBySubtractingRow:row]; 225 | 226 | XCTAssertEqualObjects(original, step4, @"Error while Adding / Subtracting Rows / Columns"); 227 | } 228 | 229 | - (void)testRowRemoval 230 | { 231 | double original[16] = { 232 | 16.0, 2.0, 3.0, 13.0, 233 | 5.0, 11.0, 10.0, 8.0, 234 | 9.0, 7.0, 6.0, 12.0, 235 | 4.0, 14.0, 15.0, 0.05 236 | }; 237 | 238 | double test[12] = { 239 | 16.0, 2.0, 3.0, 13.0, 240 | 9.0, 7.0, 6.0, 12.0, 241 | 4.0, 14.0, 15.0, 0.05 242 | }; 243 | 244 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:4 columns:4]; 245 | Matrix *resultMatrix = [originalMatrix removeRow:1]; 246 | Matrix *testMatrix = [Matrix matrixFromArray:test rows:3 columns:4]; 247 | XCTAssertEqualObjects(testMatrix, resultMatrix); 248 | CleanNSLog(@"Original:\n%@", originalMatrix); 249 | CleanNSLog(@"Test:\n%@", testMatrix); 250 | CleanNSLog(@"-removeRow: Result:\n%@", resultMatrix); 251 | } 252 | 253 | - (void)testColumnRemoval 254 | { 255 | double original[16] = { 256 | 16.0, 2.0, 3.0, 13.0, 257 | 5.0, 11.0, 10.0, 8.0, 258 | 9.0, 7.0, 6.0, 12.0, 259 | 4.0, 14.0, 15.0, 0.05 260 | }; 261 | 262 | double test[12] = { 263 | 16.0, 3.0, 13.0, 264 | 5.0, 10.0, 8.0, 265 | 9.0, 6.0, 12.0, 266 | 4.0, 15.0, 0.05 267 | }; 268 | 269 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:4 columns:4]; 270 | Matrix *resultMatrix = [originalMatrix removeColumn:1]; 271 | Matrix *testMatrix = [Matrix matrixFromArray:test rows:4 columns:3]; 272 | XCTAssertEqualObjects(testMatrix, resultMatrix); 273 | CleanNSLog(@"Original:\n%@", originalMatrix); 274 | CleanNSLog(@"Test:\n%@", testMatrix); 275 | CleanNSLog(@"-removeColumn: Result:\n%@", resultMatrix); 276 | } 277 | 278 | - (void)testRowShuffling 279 | { 280 | double original[20] = { 281 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 282 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 283 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 284 | 4.0, 40.0, 400.0, 4000.0, 40000.0 285 | }; 286 | 287 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:4 columns:5]; 288 | CleanNSLog(@"%@", originalMatrix); 289 | Matrix *shuffledMatrix = [originalMatrix copy]; 290 | [shuffledMatrix shuffleRows]; 291 | CleanNSLog(@"%@", shuffledMatrix); 292 | // Sums of columns should remain the same 293 | XCTAssertEqualObjects([originalMatrix sumsOfColumns], [shuffledMatrix sumsOfColumns]); 294 | 295 | shuffledMatrix = [originalMatrix matrixByShufflingRows]; 296 | CleanNSLog(@"%@", shuffledMatrix); 297 | // Sums of columns should remain the same 298 | XCTAssertEqualObjects([originalMatrix sumsOfColumns], [shuffledMatrix sumsOfColumns]); 299 | } 300 | 301 | - (void)testColumnShuffling 302 | { 303 | double original[20] = { 304 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 305 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 306 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 307 | 4.0, 40.0, 400.0, 4000.0, 40000.0 308 | }; 309 | 310 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:4 columns:5]; 311 | CleanNSLog(@"%@", originalMatrix); 312 | Matrix *shuffledMatrix = [originalMatrix copy]; 313 | [shuffledMatrix shuffleColumns]; 314 | CleanNSLog(@"%@", shuffledMatrix); 315 | // Sums of rows should remain the same 316 | XCTAssertEqualObjects([originalMatrix sumsOfRows], [shuffledMatrix sumsOfRows]); 317 | 318 | shuffledMatrix = [originalMatrix matrixByShufflingColumns]; 319 | CleanNSLog(@"%@", shuffledMatrix); 320 | // Sums of columns should remain the same 321 | XCTAssertEqualObjects([originalMatrix sumsOfRows], [shuffledMatrix sumsOfRows]); 322 | } 323 | 324 | - (void)testRowSplit 325 | { 326 | double original[35] = { 327 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 328 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 329 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 330 | 4.0, 40.0, 400.0, 4000.0, 40000.0, 331 | 5.0, 50.0, 500.0, 5000.0, 50000.0, 332 | 6.0, 60.0, 600.0, 6000.0, 60000.0, 333 | 7.0, 70.0, 700.0, 7000.0, 70000.0 334 | }; 335 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:7 columns:5]; 336 | 337 | double res0[15] = { 338 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 339 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 340 | 3.0, 30.0, 300.0, 3000.0, 30000.0 341 | }; 342 | Matrix *res0Matrix = [Matrix matrixFromArray:res0 rows:3 columns:5]; 343 | 344 | double res1[10] = { 345 | 4.0, 40.0, 400.0, 4000.0, 40000.0, 346 | 5.0, 50.0, 500.0, 5000.0, 50000.0 347 | }; 348 | Matrix *res1Matrix = [Matrix matrixFromArray:res1 rows:2 columns:5]; 349 | 350 | double res2[10] = { 351 | 6.0, 60.0, 600.0, 6000.0, 60000.0, 352 | 7.0, 70.0, 700.0, 7000.0, 70000.0 353 | }; 354 | Matrix *res2Matrix = [Matrix matrixFromArray:res2 rows:2 columns:5]; 355 | 356 | NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet]; 357 | [indexes addIndex:3]; 358 | [indexes addIndex:5]; 359 | NSArray *segments = [originalMatrix rowWiseSplitAtIndexes:indexes]; 360 | 361 | XCTAssertEqualObjects(segments[0], res0Matrix, @"Segments not equal"); 362 | XCTAssertEqualObjects(segments[1], res1Matrix, @"Segments not equal"); 363 | XCTAssertEqualObjects(segments[2], res2Matrix, @"Segments not equal"); 364 | } 365 | 366 | - (void)testColumnSplit 367 | { 368 | double original[28] = { 369 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 10001.0, 10002.0, 370 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 20001.0, 20002.0, 371 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 30001.0, 30002.0, 372 | 4.0, 40.0, 400.0, 4000.0, 40000.0, 40001.0, 40002.0 373 | }; 374 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:4 columns:7]; 375 | 376 | double res0[12] = { 377 | 1.0, 10.0, 100.0, 378 | 2.0, 20.0, 200.0, 379 | 3.0, 30.0, 300.0, 380 | 4.0, 40.0, 400.0 381 | }; 382 | Matrix *res0Matrix = [Matrix matrixFromArray:res0 rows:4 columns:3]; 383 | 384 | double res1[8] = { 385 | 1000.0, 10000.0, 386 | 2000.0, 20000.0, 387 | 3000.0, 30000.0, 388 | 4000.0, 40000.0 389 | }; 390 | Matrix *res1Matrix = [Matrix matrixFromArray:res1 rows:4 columns:2]; 391 | 392 | double res2[8] = { 393 | 10001.0, 10002.0, 394 | 20001.0, 20002.0, 395 | 30001.0, 30002.0, 396 | 40001.0, 40002.0 397 | }; 398 | Matrix *res2Matrix = [Matrix matrixFromArray:res2 rows:4 columns:2]; 399 | 400 | NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet]; 401 | [indexes addIndex:3]; 402 | [indexes addIndex:5]; 403 | NSArray *segments = [originalMatrix columnWiseSplitAtIndexes:indexes]; 404 | 405 | XCTAssertEqualObjects(segments[0], res0Matrix, @"Segments not equal"); 406 | XCTAssertEqualObjects(segments[1], res1Matrix, @"Segments not equal"); 407 | XCTAssertEqualObjects(segments[2], res2Matrix, @"Segments not equal"); 408 | } 409 | 410 | - (void)testRowPartitioningExact 411 | { 412 | double original[20] = { 413 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 414 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 415 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 416 | 4.0, 40.0, 400.0, 4000.0, 40000.0 417 | }; 418 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:4 columns:5]; 419 | 420 | double partition0[10] = { 421 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 422 | 2.0, 20.0, 200.0, 2000.0, 20000.0 423 | }; 424 | Matrix *partition0Matrix = [Matrix matrixFromArray:partition0 rows:2 columns:5]; 425 | 426 | double partition1[10] = { 427 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 428 | 4.0, 40.0, 400.0, 4000.0, 40000.0 429 | }; 430 | Matrix *partition1Matrix = [Matrix matrixFromArray:partition1 rows:2 columns:5]; 431 | 432 | NSArray *partitions = [originalMatrix rowWisePartition:2]; 433 | XCTAssertEqualObjects(partitions[0], partition0Matrix, @"Partitions not equal"); 434 | XCTAssertEqualObjects(partitions[1], partition1Matrix, @"Partitions not equal"); 435 | } 436 | 437 | - (void)testRowPartitioningRemainder 438 | { 439 | double original[25] = { 440 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 441 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 442 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 443 | 4.0, 40.0, 400.0, 4000.0, 40000.0, 444 | 5.0, 50.0, 500.0, 5000.0, 50000.0 445 | }; 446 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:5 columns:5]; 447 | 448 | double partition0[10] = { 449 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 450 | 2.0, 20.0, 200.0, 2000.0, 20000.0 451 | }; 452 | Matrix *partition0Matrix = [Matrix matrixFromArray:partition0 rows:2 columns:5]; 453 | 454 | double partition1[10] = { 455 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 456 | 4.0, 40.0, 400.0, 4000.0, 40000.0 457 | }; 458 | Matrix *partition1Matrix = [Matrix matrixFromArray:partition1 rows:2 columns:5]; 459 | 460 | double partition2[5] = { 461 | 5.0, 50.0, 500.0, 5000.0, 50000.0 462 | }; 463 | Matrix *partition2Matrix = [Matrix matrixFromArray:partition2 rows:1 columns:5]; 464 | 465 | NSArray *partitions = [originalMatrix rowWisePartition:2]; 466 | XCTAssertEqualObjects(partitions[0], partition0Matrix, @"Partitions not equal"); 467 | XCTAssertEqualObjects(partitions[1], partition1Matrix, @"Partitions not equal"); 468 | XCTAssertEqualObjects(partitions[2], partition2Matrix, @"Partitions not equal"); 469 | } 470 | 471 | - (void)testColumnPartitioningExact 472 | { 473 | double original[20] = { 474 | 1.0, 10.0, 100.0, 1000.0, 475 | 2.0, 20.0, 200.0, 2000.0, 476 | 3.0, 30.0, 300.0, 3000.0, 477 | 4.0, 40.0, 400.0, 4000.0, 478 | 5.0, 50.0, 500.0, 5000.0 479 | }; 480 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:5 columns:4]; 481 | 482 | double partition0[10] = { 483 | 1.0, 10.0, 484 | 2.0, 20.0, 485 | 3.0, 30.0, 486 | 4.0, 40.0, 487 | 5.0, 50.0 488 | }; 489 | Matrix *partition0Matrix = [Matrix matrixFromArray:partition0 rows:5 columns:2]; 490 | 491 | double partition1[10] = { 492 | 100.0, 1000.0, 493 | 200.0, 2000.0, 494 | 300.0, 3000.0, 495 | 400.0, 4000.0, 496 | 500.0, 5000.0 497 | }; 498 | Matrix *partition1Matrix = [Matrix matrixFromArray:partition1 rows:5 columns:2]; 499 | 500 | NSArray *partitions = [originalMatrix columnWisePartition:2]; 501 | XCTAssertEqualObjects(partitions[0], partition0Matrix, @"Partitions not equal"); 502 | XCTAssertEqualObjects(partitions[1], partition1Matrix, @"Partitions not equal"); 503 | } 504 | 505 | - (void)testColumnPartitioningRemainder 506 | { 507 | double original[25] = { 508 | 1.0, 10.0, 100.0, 1000.0, 10000.0, 509 | 2.0, 20.0, 200.0, 2000.0, 20000.0, 510 | 3.0, 30.0, 300.0, 3000.0, 30000.0, 511 | 4.0, 40.0, 400.0, 4000.0, 40000.0, 512 | 5.0, 50.0, 500.0, 5000.0, 50000.0 513 | }; 514 | Matrix *originalMatrix = [Matrix matrixFromArray:original rows:5 columns:5]; 515 | 516 | double partition0[10] = { 517 | 1.0, 10.0, 518 | 2.0, 20.0, 519 | 3.0, 30.0, 520 | 4.0, 40.0, 521 | 5.0, 50.0 522 | }; 523 | Matrix *partition0Matrix = [Matrix matrixFromArray:partition0 rows:5 columns:2]; 524 | 525 | double partition1[10] = { 526 | 100.0, 1000.0, 527 | 200.0, 2000.0, 528 | 300.0, 3000.0, 529 | 400.0, 4000.0, 530 | 500.0, 5000.0 531 | }; 532 | Matrix *partition1Matrix = [Matrix matrixFromArray:partition1 rows:5 columns:2]; 533 | 534 | double partition2[5] = { 535 | 10000.0, 536 | 20000.0, 537 | 30000.0, 538 | 40000.0, 539 | 50000.0 540 | }; 541 | Matrix *partition2Matrix = [Matrix matrixFromArray:partition2 rows:5 columns:1]; 542 | 543 | NSArray *partitions = [originalMatrix columnWisePartition:2]; 544 | XCTAssertEqualObjects(partitions[0], partition0Matrix, @"Partitions not equal"); 545 | XCTAssertEqualObjects(partitions[1], partition1Matrix, @"Partitions not equal"); 546 | XCTAssertEqualObjects(partitions[2], partition2Matrix, @"Partitions not equal"); 547 | } 548 | 549 | - (void)testApplyMatrix 550 | { 551 | // Test by applying matrices of different values and checking the sum 552 | Matrix *large = [Matrix matrixOfRows:100 columns:100 value:1]; 553 | Matrix *small = [Matrix matrixOfRows:10 columns:10 value:0]; 554 | XCTAssert(large.sum == 10000, @"Sum incorrect"); 555 | [large applyMatrix:small i:50 j:50]; 556 | XCTAssert(large.sum == 9900, @"Sum incorrect"); 557 | [large applyMatrix:small i:10 j:10]; 558 | XCTAssert(large.sum == 9800, @"Sum incorrect"); 559 | [large applyMatrix:small i:15 j:15]; 560 | XCTAssert(large.sum == 9725, @"Sum incorrect"); 561 | [large applyMatrix:small i:55 j:55]; 562 | XCTAssert(large.sum == 9650, @"Sum incorrect"); 563 | [large applyMatrix:small i:55 j:55]; 564 | XCTAssert(large.sum == 9650, @"Sum incorrect"); 565 | [large applyMatrix:small i:50 j:55]; 566 | XCTAssert(large.sum == 9625, @"Sum incorrect"); 567 | } 568 | 569 | @end 570 | -------------------------------------------------------------------------------- /YCMatrixTests/YCMatrixMapTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // YCMatrixMapTests.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | @import XCTest; 28 | @import YCMatrix; 29 | 30 | #define ARC4RANDOM_MAX 0x100000000 31 | 32 | // Definitions for convenience logging functions (without date/object and title logging). 33 | #define CleanNSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 34 | #define TitleNSLog(FORMAT, ...) fprintf(stderr,"\n%s\n_____________________________________\n\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 35 | 36 | @interface YCMatrixMapTests : XCTestCase 37 | 38 | @end 39 | 40 | @implementation YCMatrixMapTests 41 | 42 | - (void)testMinMaxMapping 43 | { 44 | Matrix *low = [Matrix matrixOfRows:4 columns:5 value:3]; 45 | Matrix *high = [Matrix matrixOfRows:4 columns:5 value:8]; 46 | Matrix *original = [Matrix uniformRandomLowerBound:low upperBound:high]; 47 | Matrix *mapping = [original rowWiseMapToDomain:YCMakeDomain(0, 1) basis:MinMax]; 48 | Matrix *inverse = [original rowWiseInverseMapFromDomain:YCMakeDomain(0, 1) basis:MinMax]; 49 | Matrix *mapped = [original matrixByRowWiseMapUsing:mapping]; 50 | Matrix *copy = [mapped matrixByRowWiseMapUsing:inverse]; 51 | XCTAssert([copy isEqualToMatrix:original tolerance:1E-9], @"Mapping failed"); 52 | } 53 | 54 | - (void)testStDevMapping 55 | { 56 | Matrix *low = [Matrix matrixOfRows:4 columns:5 value:3]; 57 | Matrix *high = [Matrix matrixOfRows:4 columns:5 value:8]; 58 | Matrix *original = [Matrix uniformRandomLowerBound:low upperBound:high]; 59 | Matrix *mapping = [original rowWiseMapToDomain:YCMakeDomain(-1, 2) basis:StDev]; 60 | Matrix *inverse = [original rowWiseInverseMapFromDomain:YCMakeDomain(-1, 2) basis:StDev]; 61 | Matrix *mapped = [original matrixByRowWiseMapUsing:mapping]; 62 | Matrix *copy = [mapped matrixByRowWiseMapUsing:inverse]; 63 | XCTAssert([copy isEqualToMatrix:original tolerance:1E-9], @"Mapping failed"); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /YCMatrixTests/YCMatrixNSArrayTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // YCMatrixNSArrayTests.m 3 | // YCMatrix 4 | // 5 | // Created by Ioannis Chatzikonstantinou on 14/1/16. 6 | // Copyright © 2016 Ioannis Chatzikonstantinou. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | @import YCMatrix; 11 | 12 | @interface YCMatrixNSArrayTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation YCMatrixNSArrayTests 17 | 18 | - (void)testArrayMin 19 | { 20 | double v1[10] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; 21 | double v2[10] = {19, 18, 17, 16, 15, 14, 13, 12, 11, 10}; 22 | double v3[10] = {20, 20, 20, 10, 10, 10, 10, 20, 20, 20}; 23 | double vt[10] = {10, 11, 12, 10, 10, 10, 10, 12, 11, 10}; 24 | 25 | Matrix *m1 = [Matrix matrixFromArray:v1 rows:10 columns:1]; 26 | Matrix *m2 = [Matrix matrixFromArray:v2 rows:10 columns:1]; 27 | Matrix *m3 = [Matrix matrixFromArray:v3 rows:10 columns:1]; 28 | Matrix *mt = [Matrix matrixFromArray:vt rows:10 columns:1]; 29 | 30 | NSArray *matrixArray = @[m1, m2, m3]; 31 | 32 | Matrix *mins = [matrixArray matrixMin]; 33 | 34 | XCTAssert([mins isEqualTo:mt], @"Error in computing min matrix of array"); 35 | } 36 | 37 | - (void)testArrayMax 38 | { 39 | double v1[10] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; 40 | double v2[10] = {19, 18, 17, 16, 15, 14, 13, 12, 11, 10}; 41 | double v3[10] = {20, 20, 20, 10, 10, 10, 10, 20, 20, 20}; 42 | double vt[10] = {20, 20, 20, 16, 15, 15, 16, 20, 20, 20}; 43 | 44 | Matrix *m1 = [Matrix matrixFromArray:v1 rows:10 columns:1]; 45 | Matrix *m2 = [Matrix matrixFromArray:v2 rows:10 columns:1]; 46 | Matrix *m3 = [Matrix matrixFromArray:v3 rows:10 columns:1]; 47 | Matrix *mt = [Matrix matrixFromArray:vt rows:10 columns:1]; 48 | 49 | NSArray *matrixArray = @[m1, m2, m3]; 50 | 51 | Matrix *maxs = [matrixArray matrixMax]; 52 | 53 | XCTAssert([maxs isEqualTo:mt], @"Error in computing max matrix of array"); 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /YCMatrixTests/YCMatrixPerformanceTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // YCMatrixPerformanceTests.m 3 | // YCMatrix 4 | // 5 | // Created by Ioannis Chatzikonstantinou on 28/1/16. 6 | // Copyright © 2016 Ioannis Chatzikonstantinou. All rights reserved. 7 | // 8 | 9 | #import 10 | @import YCMatrix; 11 | 12 | @interface YCMatrixPerformanceTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation YCMatrixPerformanceTests 17 | 18 | - (void)testVDSPAddPerformance { 19 | 20 | Matrix *lower = [Matrix matrixOfRows:10000 columns:2000 value:0]; 21 | Matrix *upper = [Matrix matrixOfRows:10000 columns:2000 value:1]; 22 | 23 | Matrix *A = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 24 | Matrix *B = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 25 | 26 | [self measureBlock:^{ 27 | [A matrixByAdding:B]; 28 | }]; 29 | } 30 | 31 | - (void)testBLASMultiplyScalarAndAddPerformance { 32 | 33 | Matrix *lower = [Matrix matrixOfRows:10000 columns:2000 value:0]; 34 | Matrix *upper = [Matrix matrixOfRows:10000 columns:2000 value:1]; 35 | 36 | Matrix *A = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 37 | Matrix *B = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 38 | 39 | [self measureBlock:^{ 40 | [A matrixByMultiplyingWithScalar:1 AndAdding:B]; 41 | }]; 42 | } 43 | 44 | - (void)testCAddPerformance { 45 | 46 | Matrix *lower = [Matrix matrixOfRows:10000 columns:2000 value:0]; 47 | Matrix *upper = [Matrix matrixOfRows:10000 columns:2000 value:1]; 48 | 49 | Matrix *A = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 50 | Matrix *B = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 51 | 52 | double *ma = A->matrix; 53 | double *mb = B->matrix; 54 | 55 | [self measureBlock:^{ 56 | 57 | // Need to include memory allocation as well here 58 | Matrix *C = [Matrix matrixLike:A]; 59 | double *mc = C->matrix; 60 | 61 | #pragma vector always 62 | for (int i=0, j=(int)A.count; imatrix; 105 | double *mb = B->matrix; 106 | 107 | [self measureBlock:^{ 108 | 109 | // Need to include memory allocation as well here 110 | Matrix *C = [Matrix matrixLike:A]; 111 | double *mc = C->matrix; 112 | 113 | #pragma vector always 114 | for (int i=0, j=(int)A.count; irows*A->columns, 10, A->matrix, 1); 131 | }]; 132 | } 133 | 134 | - (void)testVDSPMultiplyScalarPerformance 135 | { 136 | Matrix *lower = [Matrix matrixOfRows:10000 columns:2000 value:0]; 137 | Matrix *upper = [Matrix matrixOfRows:10000 columns:2000 value:1]; 138 | 139 | Matrix *A = [Matrix uniformRandomLowerBound:lower upperBound:upper]; 140 | 141 | [self measureBlock:^{ 142 | [A multiplyWithScalar:10]; 143 | }]; 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /YCMatrixTests/YCMatrixTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /YCMatrixTests/YCMatrixTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // YCMatrixTests.m 3 | // 4 | // YCMatrix 5 | // 6 | // Copyright (c) 2013 - 2016 Ioannis (Yannis) Chatzikonstantinou. All rights reserved. 7 | // http://yconst.com 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | //References for this Document: 28 | // http://en.wikipedia.org/wiki/Cholesky_decomposition 29 | 30 | @import XCTest; 31 | @import YCMatrix; 32 | 33 | #define ARC4RANDOM_MAX 0x100000000 34 | 35 | // Definitions for convenience logging functions (without date/object and title logging). 36 | #define CleanNSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 37 | #define TitleNSLog(FORMAT, ...) fprintf(stderr,"\n%s\n_____________________________________\n\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 38 | 39 | @interface YCMatrixTests : XCTestCase 40 | 41 | @end 42 | 43 | @implementation YCMatrixTests 44 | 45 | - (void)testIdentity 46 | { 47 | TitleNSLog(@"Identity Matrix Test"); 48 | double idm_ref_array[15] = { 1.0, 0.0, 0.0, 49 | 0.0, 1.0, 0.0, 50 | 0.0, 0.0, 1.0, 51 | 0.0, 0.0, 0.0, 52 | 0.0, 0.0, 0.0 }; 53 | Matrix *idmRef = [Matrix matrixFromArray:idm_ref_array rows:5 columns:3]; 54 | Matrix *idm = [Matrix identityOfRows:5 columns:3]; 55 | CleanNSLog(@"%@",idm); 56 | XCTAssertEqualObjects(idm, idmRef, @"Error in creating Identity Matrix"); 57 | } 58 | 59 | - (void)testOnes 60 | { 61 | Matrix *template = [Matrix matrixOfRows:5 columns:5 value:1]; 62 | Matrix *match = [Matrix onesLike:template]; 63 | XCTAssertEqualObjects(template, match, @"Error in creating matrix of ones."); 64 | } 65 | 66 | - (void)testAbsolute 67 | { 68 | Matrix *absoluteMatrix = [Matrix uniformRandomRows:10 columns:10 domain:YCMakeDomain(-1.0, 1.0)]; 69 | [absoluteMatrix absolute]; 70 | for (int i=0, k=absoluteMatrix.rows; i= 0, @"Negative value in absolute matrix"); 75 | } 76 | } 77 | } 78 | 79 | - (void)testRetrieval 80 | { 81 | TitleNSLog(@"Simple Array Test"); 82 | double simple_array[9] = { 1.0, 2.0, 3.0, 83 | 4.0, 5.0, 6.0, 84 | 7.0, 8.0, 9.0 }; 85 | Matrix *simple_matrix = [Matrix matrixFromArray:simple_array rows:3 columns:3]; 86 | CleanNSLog(@"%@",simple_matrix); 87 | 88 | // Perform various get item tests 89 | TitleNSLog(@"Get Items Test"); 90 | CleanNSLog(@"Value at 0,0: %f",[simple_matrix valueAtRow:0 column:0]); 91 | CleanNSLog(@"Value at 1,1: %f",[simple_matrix valueAtRow:1 column:1]); 92 | CleanNSLog(@"Value at 2,1: %f",[simple_matrix valueAtRow:2 column:1]); 93 | CleanNSLog(@"Value at 1,2: %f",[simple_matrix valueAtRow:1 column:2]); 94 | CleanNSLog(@"Value at 2,2: %f",[simple_matrix valueAtRow:2 column:2]); 95 | XCTAssertTrue([simple_matrix valueAtRow:0 column:0] == 1.0, @"GetValue error!"); 96 | XCTAssertTrue([simple_matrix valueAtRow:1 column:0] == 4.0, @"GetValue error!"); 97 | XCTAssertTrue([simple_matrix valueAtRow:2 column:0] == 7.0, @"GetValue error!"); 98 | XCTAssertTrue([simple_matrix valueAtRow:0 column:1] == 2.0, @"GetValue error!"); 99 | XCTAssertTrue([simple_matrix valueAtRow:0 column:2] == 3.0, @"GetValue error!"); 100 | XCTAssertTrue([simple_matrix valueAtRow:2 column:1] == 8.0, @"GetValue error!"); 101 | XCTAssertTrue([simple_matrix i:0 j:1] == 2.0, @"GetValue error!"); 102 | XCTAssertTrue([simple_matrix i:0 j:2] == 3.0, @"GetValue error!"); 103 | XCTAssertTrue([simple_matrix i:2 j:1] == 8.0, @"GetValue error!"); 104 | } 105 | 106 | - (void)testDiagonal 107 | { 108 | double source_array[12] = { 1.0, 2.0, 3.0, 109 | 4.0, 5.0, 6.0, 110 | 7.0, 8.0, 9.0, 111 | 1.0, 2.0, 6.0}; 112 | Matrix *sourceMatrix = [Matrix matrixFromArray:source_array rows:4 columns:3]; 113 | double target_array[3] = { 1.0, 5.0, 9.0 }; 114 | Matrix *targetMatrix = [Matrix matrixFromArray:target_array rows:3 columns:1]; 115 | Matrix *diagonal = [sourceMatrix diagonal]; 116 | XCTAssertEqualObjects(diagonal, targetMatrix, @"Error in deriving diagonal."); 117 | } 118 | 119 | - (void)testTransposition 120 | { 121 | TitleNSLog(@"Transposition"); 122 | double matrix_orig_arr[6] = { 1.0, 2.0, 3.0, 123 | 4.0, 5.0, 6.0 }; 124 | double matrix_trans_arr[6] = { 1.0, 4.0, 125 | 2.0, 5.0, 126 | 3.0, 6.0 }; 127 | Matrix *orig = [Matrix matrixFromArray:matrix_orig_arr rows:2 columns:3]; 128 | Matrix *trans = [Matrix matrixFromArray:matrix_trans_arr rows:3 columns:2]; 129 | Matrix *trans2 = [orig matrixByTransposing]; 130 | CleanNSLog(@"%@",orig); 131 | CleanNSLog(@"%@",trans); 132 | CleanNSLog(@"%@",trans2); 133 | XCTAssertEqualObjects(trans, trans2, @"M^T != Mt"); 134 | XCTAssertEqualObjects(orig, [[orig matrixByTransposing] matrixByTransposing], @"M^T^T != M"); 135 | } 136 | 137 | - (void)testDot 138 | { 139 | TitleNSLog(@"Dot Product"); 140 | double vectorarray[3] = { 1.0, 2.0, 3.0 }; 141 | Matrix *Vector = [Matrix matrixFromArray:vectorarray rows:3 columns:1]; 142 | double dotp = [Vector dotWith:Vector]; 143 | CleanNSLog(@"Dot Product: %f",dotp); 144 | XCTAssertEqual(dotp, 14.0, @"Error in calculating dot product"); 145 | } 146 | 147 | - (void)testTrace 148 | { 149 | TitleNSLog(@"Trace"); 150 | double matrix_array[9] = { 1.0, 2.0, 3.0, 151 | 4.0, 5.0, 6.0, 152 | 7.0, 8.0, 9.0 }; 153 | Matrix *tracetestm = [Matrix matrixFromArray:matrix_array rows:3 columns:3]; 154 | double trace = [[tracetestm matrixByMultiplyingWithRight:tracetestm] trace]; 155 | CleanNSLog(@"%f",trace); 156 | XCTAssertEqual(trace, 261.000, @"Trace is not correct!"); 157 | } 158 | 159 | - (void)testAdditionScalarMultiplication 160 | { 161 | TitleNSLog(@"Addition and Scalar Multiplication"); 162 | double matrix_array[9] = { 1.0, 2.0, 3.0, 163 | 4.0, 5.0, 6.0, 164 | 7.0, 8.0, 9.0 }; 165 | Matrix *testm1 = [Matrix matrixFromArray:matrix_array rows:3 columns:3]; 166 | Matrix *testm2 = [Matrix matrixFromMatrix:testm1]; 167 | Matrix *testm_add = [testm1 matrixByAdding:testm2]; 168 | Matrix *testm_ms = [testm1 matrixByMultiplyingWithScalar:2]; 169 | XCTAssertEqualObjects(testm_ms, testm_add, @"M+M != 2*M"); 170 | 171 | TitleNSLog(@"Matrix Multiplication"); 172 | CleanNSLog(@"Test Matrix 1: %ix%i",testm1->rows, testm1->columns); 173 | CleanNSLog(@"Test Matrix 2: %ix%i",testm2->rows, testm2->columns); 174 | Matrix *multResult = [testm1 matrixByMultiplyingWithRight:testm2]; 175 | CleanNSLog(@"Resulting Matrix: %ix%i",multResult->rows, multResult->columns); 176 | CleanNSLog(@"%@",multResult); 177 | } 178 | 179 | - (void)testVDSPAdd 180 | { 181 | Matrix *A = [Matrix matrixOfRows:10 columns:1 value:1]; 182 | Matrix *B = [Matrix matrixOfRows:10 columns:1 value:1]; 183 | 184 | Matrix *C = [A matrixByAdding:B]; 185 | Matrix *T = [Matrix matrixOfRows:10 columns:1 value:2]; 186 | XCTAssertEqualObjects(C, T, @"Matrix subtraction failed"); 187 | [A add:B]; 188 | XCTAssertEqualObjects(A, T, @"Matrix subtraction failed"); 189 | } 190 | 191 | - (void)testVDSPSubtract 192 | { 193 | Matrix *A = [Matrix matrixOfRows:10 columns:1 value:0]; 194 | Matrix *B = [Matrix matrixOfRows:10 columns:1 value:1]; 195 | 196 | Matrix *C = [A matrixBySubtracting:B]; 197 | Matrix *T = [Matrix matrixOfRows:10 columns:1 value:-1]; 198 | XCTAssertEqualObjects(C, T, @"Matrix subtraction failed"); 199 | [A subtract:B]; 200 | XCTAssertEqualObjects(A, T, @"Matrix subtraction failed"); 201 | } 202 | 203 | - (void)testTransposedMultiply 204 | { 205 | double simple_array[6] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; 206 | Matrix *A = [Matrix matrixFromArray:simple_array rows:2 columns:3]; 207 | CleanNSLog(@"%@",A); 208 | 209 | double simple_array_2[6] = { 2.0, 3.0, 1.0, 4.0, 0.0, 5.0 }; 210 | Matrix *B = [Matrix matrixFromArray:simple_array_2 rows:3 columns:2]; 211 | CleanNSLog(@"%@",B); 212 | 213 | Matrix *C = [A matrixByMultiplyingWithRight:B AndTransposing:YES]; 214 | CleanNSLog(@"%@",C); 215 | } 216 | 217 | - (void)testGEMMPerformance 218 | { 219 | Matrix *A = [Matrix uniformRandomRows:1000 columns:1000 domain:YCMakeDomain(0, 10)]; 220 | Matrix *B = [Matrix uniformRandomRows:1000 columns:1000 domain:YCMakeDomain(0, 10)]; 221 | 222 | [self measureBlock:^{ 223 | [A matrixByMultiplyingWithRight:B]; 224 | }]; 225 | } 226 | 227 | - (void)testGEMM 228 | { 229 | Matrix *A = [Matrix uniformRandomRows:10 columns:10 domain:YCMakeDomain(0, 10)]; 230 | Matrix *B = [Matrix uniformRandomRows:10 columns:10 domain:YCMakeDomain(0, 10)]; 231 | 232 | Matrix *ACopy = [A copy]; 233 | Matrix *BCopy = [B copy]; 234 | NSLog(@"%@", [A matrixByMultiplyingWithRight:B]); 235 | XCTAssertEqualObjects(A, ACopy); 236 | XCTAssertEqualObjects(B, BCopy); 237 | } 238 | 239 | - (void)testDictionaryContainsKey 240 | { 241 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 242 | Matrix *m1 = [Matrix uniformRandomRows:1 columns:5 domain:YCMakeDomain(0, 1)]; 243 | [dict setObject:@1 forKey:[m1 copy]]; 244 | XCTAssert([dict[m1] isEqual:@1], @"Matrix dictionary key lookup unsuccessful"); 245 | XCTAssertNil(dict[[m1 matrixByTransposing]], @"Value of transpose not nil"); 246 | } 247 | 248 | - (void)testHash 249 | { 250 | Matrix *m1 = [Matrix uniformRandomRows:50 columns:50 domain:YCMakeDomain(0, 1)]; 251 | NSLog(@"%lu", m1.hash); 252 | } 253 | 254 | - (void)testSerialization 255 | { 256 | Matrix *testm1 = [Matrix uniformRandomRows:10 columns:10 domain:YCMakeDomain(0, 10)]; 257 | NSData *serialized = [NSKeyedArchiver archivedDataWithRootObject:testm1]; 258 | Matrix *recovered = [NSKeyedUnarchiver unarchiveObjectWithData:serialized]; 259 | XCTAssertEqualObjects(testm1, recovered, @"Error in deserialization"); 260 | } 261 | 262 | @end 263 | -------------------------------------------------------------------------------- /YCMatrixTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ycmatrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yconst/YCMatrix/c169e2e3fbe40e80b38ac272462b0f731815e174/ycmatrix.png --------------------------------------------------------------------------------