├── .gitignore ├── Makefile ├── test.exe ├── readme.md ├── test.cpp ├── LICENSE └── Matrix.h /.gitignore: -------------------------------------------------------------------------------- 1 | files 2 | *.txt 3 | *.sh 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: test.cpp 2 | g++ -std=c++11 test.cpp -o test.exe -------------------------------------------------------------------------------- /test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piratf/MatrixH/HEAD/test.exe -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ##简易矩阵运算库 2 | 3 | 实现了部分矩阵运算函数,目标是尽可能简洁和高效,参考了部分开源实现代码。 4 | 所有方法放在一个头文件中实现,只需要 include 头文件即可,便于使用。 5 | 6 | 编译指令: 7 | 8 | ``` 9 | make 10 | ``` 11 | 或 12 | ``` 13 | g++ -std=c++11 -O3 14 | ``` 15 | 16 | 方法详见头文件类声明部分,详细注释在实现部分 17 | 18 | #####需要注意的部分 19 | 20 | > * warning: 取模运算符 % 被重载为 右除,便于使用。(不是矩阵取模 21 | > * warning: 可以使用泛型实例化,但使用 `complex` 类型实例化矩阵时由于 `toDouble` 函数的原因无法使用除法等相关函数。计划通过继承实现类的拆分。 22 | > * /= 运算由于在 除法部分 涉及到数值的类型转换,暂时没有优化,其他赋值运算符有优化,比运算再赋值快。 -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #ifdef __WIN32 8 | #include 9 | #endif 10 | #include "Matrix.h" 11 | using namespace std; 12 | using namespace pmh; 13 | 14 | // 矩阵大小 15 | // 超过 100 以后在普通电脑上求逆和除法会比较慢 16 | const unsigned D = 20; 17 | 18 | void inputMatrix(Matrix &m, Matrix &n) { 19 | for (unsigned i = 0; i < D; ++i) { 20 | for (unsigned j = 0; j < D; ++j) { 21 | cin >> m[i][j]; 22 | } 23 | } 24 | 25 | for (unsigned i = 0; i < D; ++i) { 26 | for (unsigned j = 0; j < D; ++j) { 27 | cin >> n[i][j]; 28 | } 29 | } 30 | 31 | return; 32 | } 33 | 34 | void AccurateTest() { 35 | 36 | Matrix m = Matrix::rand(D, D); 37 | Matrix n = Matrix::rand(D, D); 38 | 39 | #ifdef __WIN32 40 | LARGE_INTEGER freq; 41 | LARGE_INTEGER start_t, stop_t; 42 | LARGE_INTEGER freq1; 43 | LARGE_INTEGER start_t1, stop_t1; 44 | double exe_time; 45 | QueryPerformanceFrequency(&freq); 46 | // fprintf(stdout, "The frequency of your pc is %d.\n", freq.QuadPart); 47 | cout << "The frequency of your pc is " << freq.QuadPart << endl; 48 | QueryPerformanceCounter(&start_t); 49 | m.mul(m, n); 50 | QueryPerformanceCounter(&stop_t); 51 | exe_time = 1e3 * (stop_t.QuadPart - start_t.QuadPart) / freq.QuadPart; 52 | cout << "use Time of mul: " << exe_time << "ms" << endl; 53 | // fprintf(stdout, "Your program executed time is %fms.\n", exe_time); 54 | 55 | 56 | QueryPerformanceFrequency(&freq1); 57 | // fprintf(stdout, "The frequency of your pc is %d.\n", freq.QuadPart); 58 | cout << "The frequency of your pc is " << freq1.QuadPart << endl; 59 | QueryPerformanceCounter(&start_t1); 60 | m.smul(m, n); 61 | QueryPerformanceCounter(&stop_t1); 62 | exe_time = 1e3 * (stop_t1.QuadPart - start_t1.QuadPart) / freq1.QuadPart; 63 | cout << "use Time of smul: " << exe_time << "ms" << endl; 64 | // fprintf(stdout, "Your program executed time is %fms.\n", exe_time); 65 | #endif 66 | } 67 | 68 | void testWithPrint() { 69 | ios::sync_with_stdio(false); 70 | srand((unsigned)time(NULL)); 71 | 72 | Matrix m = Matrix::rand(D, D); 73 | Matrix n = Matrix::rand(D, D); 74 | 75 | cout << "print" << endl; 76 | cout << m << endl; 77 | cout << n << endl; 78 | cout << "swap" << endl; 79 | m.swap(n); 80 | cout << "print" << endl; 81 | cout << m << endl; 82 | cout << n << endl; 83 | cout << "get contribute" << endl; 84 | cout << m.row() << ' ' << m.col() << endl; 85 | cout << m.max() << ' ' << m.min() << ' ' << m.avg() << endl; 86 | cout << "operator +" << endl; 87 | cout << m + n << endl; 88 | cout << "operator -" << endl; 89 | cout << m - n << endl; 90 | 91 | 92 | cout << "operator *" << endl; 93 | cout << m *n << endl; 94 | cout << "operator /" << endl; 95 | cout << m / n << endl; 96 | cout << "operator %" << endl; 97 | cout << m % n << endl; 98 | cout << "cut" << endl; 99 | cout << m.cut(0, m.row() / 2, 0, m.col() / 2); 100 | cout << "eig" << endl; 101 | cout << n.eig() << endl; 102 | // cout << "cond2" << endl; 103 | // cout << n.cond2() << endl; 104 | cout << "operator ^" << endl; 105 | cout << (m ^ 15) << endl; 106 | cout << "avg" << endl; 107 | cout << m.avg() << endl; 108 | cout << "copy" << endl; 109 | n = m; 110 | cout << "cov" << endl; 111 | cout << m.cov() << endl; 112 | cout << "inv" << endl; 113 | cout << m.inv() << endl; 114 | // cout << "hess" << endl; 115 | // cout << m.hess() << endl; 116 | cout << "cond2" << endl; 117 | cout << m.cond2() << endl; 118 | cout << "eye" << endl; 119 | cout << Matrix::eye(D, D) << endl; 120 | cout << "randn" << endl; 121 | cout << Matrix::randn(5, 10) << endl; 122 | ios::sync_with_stdio(true); 123 | } 124 | 125 | void testRandnWithMap() { 126 | std::map hist; 127 | 128 | for (int n = 0; n < 10000; ++n) { 129 | // cout << Matrix::randn() << endl; 130 | ++hist[std::round(Matrix::randn())]; 131 | } 132 | 133 | for (auto p : hist) { 134 | std::cout << std::fixed << std::setprecision(1) << std::setw(2) 135 | << p.first << ' ' 136 | << std::string(p.second / 200, '*') << '\n'; 137 | } 138 | } 139 | 140 | void test() { 141 | Matrix m = Matrix::rand(D, D); 142 | 143 | cout << m.max() << endl; 144 | cout << m.min() << endl; 145 | cout << m.avg() << endl; 146 | return; 147 | } 148 | 149 | int main() { 150 | ios::sync_with_stdio(false); 151 | freopen("test.txt", "r", stdin); 152 | freopen("output.txt", "w", stdout); 153 | 154 | testWithPrint(); 155 | // testRandnWithMap(); 156 | test(); 157 | // AccurateTest(); 158 | 159 | return 0; 160 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /Matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef MATRIX_H 2 | #define MATRIX_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | using std::cout; 17 | using std::endl; 18 | 19 | namespace piratfMatrixH { 20 | 21 | using vecSizeT = size_t; 22 | 23 | // 单线程随机数生成器,使用 setRand 24 | static std::mt19937 *_genPtr; 25 | static std::normal_distribution normDis(0, 1); 26 | static std::uniform_real_distribution unifDoubleDis(0, 1); 27 | static std::uniform_real_distribution unifFloatDis(0, 1); 28 | static std::uniform_int_distribution unifIntDis(0, 65535); 29 | 30 | // 辅助代码 31 | // ========================================= 32 | // 用来判断类别是否相同 33 | // ========================================= 34 | template 35 | struct SameType { 36 | static const bool isSame = false; 37 | }; 38 | 39 | template 40 | struct SameType { 41 | static const bool isSame = true; 42 | }; 43 | 44 | // 用来判断类别是否是复数 45 | // ========================================= 46 | template 47 | struct ComplexType { 48 | static const bool isComplex = false; 49 | }; 50 | 51 | template 52 | struct ComplexType > { 53 | static const bool isComplex = true; 54 | }; 55 | 56 | // 重载判断复数的大小 57 | // ========================================= 58 | template 59 | bool operator < (const std::complex &lhs, const std::complex &rhs) { 60 | return lhs.real() < rhs.real(); 61 | } 62 | 63 | template 64 | bool operator < (const std::complex &lhs, const T &rhs) { 65 | return lhs.real() < rhs.real(); 66 | } 67 | 68 | 69 | class Exception { 70 | 71 | public: 72 | explicit Exception(const std::string &_m): message(_m) { 73 | } 74 | 75 | void printMessage() const { 76 | std::cout << message << std::endl; 77 | } 78 | 79 | private: 80 | std::string message; 81 | }; 82 | 83 | // 矩阵的逆不存在 - 异常类 84 | class NoInverseException : public Exception { 85 | 86 | }; 87 | 88 | // 复数矩阵无法进行这个运算 - 异常类 89 | class ComplexTypeCantDo : public Exception { 90 | 91 | }; 92 | 93 | // 辅助代码结束 94 | // ========================================= 95 | 96 | template 97 | class Matrix { 98 | public: 99 | Matrix() = default; 100 | Matrix(Matrix &&other); 101 | Matrix(const Matrix &other); 102 | Matrix(vecSizeT _x); 103 | Matrix(vecSizeT _x, vecSizeT _y); 104 | Matrix(std::vector > dvec); 105 | 106 | static void inline setRand(); 107 | static void inline setRand(std::mt19937 *_p); 108 | static T inline randn(); 109 | static Matrix inline randn(vecSizeT n); 110 | static Matrix inline randn(vecSizeT r, vecSizeT c); 111 | 112 | static T inline rand(); 113 | static Matrix inline rand(vecSizeT n); 114 | static Matrix inline rand(vecSizeT r, vecSizeT c); 115 | 116 | // static T inline random(); 117 | 118 | void inline clear(); 119 | void inline swap(Matrix &rhs) { 120 | data.swap(rhs.getData()); 121 | } 122 | void inline setZero(); 123 | std::vector > &getData(); 124 | const std::vector > &getData() const ; 125 | 126 | vecSizeT inline col() const; 127 | vecSizeT inline row() const; 128 | 129 | Matrix inline cut(vecSizeT rs, vecSizeT re, vecSizeT cs, vecSizeT ce) const; 130 | Matrix inline row(vecSizeT index) const; 131 | 132 | Matrix toDouble() const; 133 | Matrix inv() const; 134 | Matrix cov() const; 135 | Matrix hess() const; 136 | Matrix> eig(double eps = 1e-12, unsigned LOOP = 100000) const; 137 | 138 | void mul(Matrix &ret, const Matrix &other) const ; 139 | void smul(Matrix &ret, const Matrix &other) const ; 140 | void StrassenMul(vecSizeT rs, vecSizeT re, vecSizeT cs, vecSizeT ce, const Matrix &other, Matrix &ret) const ; 141 | Matrix div(const Matrix &other) const ; 142 | Matrix rdiv(const Matrix &other) const ; 143 | 144 | T inline max() const; 145 | T inline min() const; 146 | T inline avg() const; 147 | std::complex cond2() const; 148 | 149 | static T vectorDotProduct(const std::vector lhs, std::vector rhs); 150 | static Matrix cov(const Matrix &input); 151 | static Matrix eye(vecSizeT _x, vecSizeT _y); 152 | static T inline avg(const std::vector &vec); 153 | 154 | bool inline empty() const; 155 | bool inline isSquare() const; 156 | bool inline isSingular() const; 157 | 158 | std::complex det() const; 159 | Matrix getTransposition() const; 160 | 161 | std::vector &operator [](vecSizeT index); 162 | const std::vector &operator [](vecSizeT index) const; 163 | Matrix operator = (const Matrix &other); 164 | Matrix operator = (Matrix &&other); 165 | Matrix inline operator + (const Matrix &other) const ; 166 | Matrix inline operator - (const Matrix &other) const ; 167 | Matrix inline operator * (const Matrix &other) const ; 168 | Matrix inline operator / (const Matrix &other) const ; 169 | Matrix inline operator % (const Matrix &other) const ; 170 | Matrix inline operator *= (const Matrix &other); 171 | Matrix inline operator += (const Matrix &other); 172 | Matrix inline operator -= (const Matrix &other); 173 | Matrix inline operator /= (const Matrix &other); 174 | 175 | /** 176 | * 矩阵快速幂 177 | * 参数需要一个当前类类型成员,出于泛型考虑使用 friend 实现 178 | * 友元模板实现 179 | */ 180 | friend Matrix inline operator ^ (const Matrix &mat, unsigned exponent) { 181 | Matrix ans = eye(mat.row(), mat.col()); 182 | Matrix src = mat; 183 | 184 | for (; exponent; exponent >>= 1) { 185 | if (exponent & 1) { 186 | ans *= src; 187 | } 188 | 189 | src *= src; 190 | } 191 | 192 | return ans; 193 | } 194 | 195 | /** 196 | * 友元模板实现 197 | */ 198 | friend std::ostream &operator << (std::ostream &o, const Matrix &mat) { 199 | // 判断要输出的数是否是 double 类型 200 | bool dFlag = SameType::isSame; 201 | 202 | if (dFlag) { 203 | using std::ios; 204 | using std::setprecision; 205 | o << setiosflags(ios::right) << setiosflags(ios::scientific) << setprecision(4); 206 | } 207 | 208 | for (vecSizeT i = 0; i != mat.data.size(); ++i) { 209 | for (vecSizeT j = 0; j != mat.data[i].size(); ++j) { 210 | if (dFlag) { 211 | o << std::setw(12) << mat.data[i][j] << ' '; 212 | } else { 213 | o << mat.data[i][j] << ' '; 214 | } 215 | } 216 | 217 | if (i < mat.data.size() - 1) { 218 | o << '\n'; 219 | } 220 | } 221 | 222 | o << std::endl; 223 | return o; 224 | } 225 | 226 | private: 227 | std::vector< std::vector > data; 228 | static std::mt19937 gen; 229 | }; 230 | 231 | /** 232 | * 移动构造 233 | */ 234 | template 235 | Matrix::Matrix(Matrix &&other) { 236 | data.swap(other.data); 237 | } 238 | 239 | /** 240 | * 拷贝构造 241 | */ 242 | template 243 | Matrix::Matrix(const Matrix &other) { 244 | data = other.getData(); 245 | } 246 | 247 | /** 248 | * 建立一个n行的空矩阵 249 | */ 250 | template 251 | Matrix::Matrix(vecSizeT _x) { 252 | std::vector< std::vector > temp(_x); 253 | data = temp; 254 | } 255 | 256 | /** 257 | * 通过矩阵的行列数构造空矩阵 258 | */ 259 | template 260 | Matrix::Matrix(vecSizeT _x, vecSizeT _y) { 261 | std::vector< std::vector > temp(_x, std::vector(_y)); 262 | data = temp; 263 | } 264 | 265 | /** 266 | * 矩阵深拷贝构造函数,调用了vector的拷贝方法 267 | */ 268 | template 269 | Matrix::Matrix(std::vector > dvec) { 270 | data = dvec; 271 | } 272 | 273 | /** 274 | * 生成一个指定大小的单位阵 275 | * @author piratf 276 | * @param _x 行数 277 | * @param _y 列数 278 | * @return 一个单位矩阵 279 | */ 280 | template 281 | Matrix Matrix::eye(vecSizeT _x, vecSizeT _y) { 282 | Matrix mat(_x, _y); 283 | 284 | for (vecSizeT i = 0; i < _x; ++i) { 285 | for (vecSizeT j = 0; j < _y; ++j) { 286 | if (i == j) { 287 | mat.data[i][j] = 1; 288 | } 289 | } 290 | } 291 | 292 | return mat; 293 | } 294 | 295 | /** 296 | * 获得矩阵的转置 297 | * @author piratf 298 | * @return 新的矩阵,内容为原矩阵的转置 299 | */ 300 | template 301 | Matrix Matrix::getTransposition() const { 302 | decltype(data.size()) sizeRow = data.size(); 303 | 304 | if (sizeRow == 0) { 305 | std::cerr << "error** Matrix::getTransposition -> empty Matrix!" << std::endl; 306 | } 307 | 308 | using vecSizeT = decltype(data.size()); 309 | vecSizeT sizeCol = data[0].size(); 310 | 311 | Matrix tran(sizeCol, sizeRow); 312 | 313 | for (vecSizeT i = 0; i < sizeRow; ++i) { 314 | for (vecSizeT j = 0; j < sizeCol; ++j) { 315 | tran.data[j][i] = data[i][j]; 316 | } 317 | } 318 | 319 | return tran; 320 | } 321 | 322 | /** 323 | * 静态函数:获取两个向量的点乘结果 324 | * @author piratf 325 | * @param lhs 向量1 326 | * @param rhs 向量2 327 | * @return double:点乘的结果 328 | */ 329 | template 330 | T Matrix::vectorDotProduct(const std::vector lhs, std::vector rhs) { 331 | T ans = 0; 332 | 333 | for (decltype(lhs.size()) i = 0; i != lhs.size(); ++i) { 334 | ans += lhs[i] * rhs[i]; 335 | } 336 | 337 | return ans; 338 | } 339 | 340 | /** 341 | * 一个向量的均值 342 | */ 343 | template 344 | T Matrix::avg(const std::vector &vec) { 345 | T sum = 0; 346 | 347 | for (T var : vec) { 348 | sum += var; 349 | } 350 | 351 | return sum / vec.size(); 352 | } 353 | 354 | /** 355 | * 矩阵的协方差矩阵 356 | */ 357 | template 358 | Matrix Matrix::cov() const { 359 | #ifndef NOTEMPTY 360 | #define NOTEMPTY 361 | assert(!empty()); 362 | #endif 363 | const vecSizeT sizeRow = row(); 364 | const vecSizeT sizeCol = col(); 365 | auto mat = this ->getTransposition(); 366 | std::vector avgVec; 367 | 368 | // 对于每一行求其均值 369 | for (auto &row : mat.data) { 370 | avgVec.push_back(avg(row)); 371 | } 372 | 373 | // 获得协方差矩阵参数 374 | Matrix temp(sizeRow, sizeCol); 375 | 376 | for (vecSizeT i = 0; i != sizeRow; ++i) { 377 | for (vecSizeT j = 0; j != sizeCol; ++j) { 378 | temp.data[i][j] = mat.data[i][j] - avgVec[i]; 379 | } 380 | } 381 | 382 | // 获得协方差矩阵 383 | Matrix cov(sizeRow, sizeRow); 384 | 385 | for (vecSizeT i = 0; i != sizeRow; ++i) { 386 | for (vecSizeT j = 0; j != sizeRow; ++j) { 387 | cov.data[i][j] = Matrix::vectorDotProduct(temp.data[i], temp.data[j]) / (sizeCol - 1); 388 | } 389 | } 390 | 391 | return cov; 392 | } 393 | 394 | /** 395 | * 获得样本矩阵的协方差矩阵 396 | * 参数矩阵中的各样本需按行排列 397 | * @author piratf 398 | * @return 一个新的协方差矩阵 399 | */ 400 | template 401 | Matrix Matrix::cov(const Matrix &input) { 402 | return input.cov(); 403 | } 404 | 405 | /** 406 | * 判断是否是空矩阵 407 | * @author piratf 408 | * @return 1 : 0 -> 空矩阵 : 不是空矩阵 409 | */ 410 | template 411 | bool Matrix::empty() const { 412 | return !data.size(); 413 | } 414 | 415 | /** 416 | * 判断矩阵是否是方阵 417 | * @author piratf 418 | * @return 1 : 0 -> 方阵 : 不是方阵 419 | */ 420 | template 421 | bool Matrix::isSquare() const { 422 | return empty() ? 0 : data.size() == data[0].size(); 423 | } 424 | 425 | /** 426 | * 求矩阵行列式 427 | * @author piratf 428 | * @return double: 行列式的值 429 | */ 430 | template 431 | std::complex Matrix::det() const { 432 | // 所有特征根的乘积 433 | auto e = eig(); 434 | std::complex ret = e[0]; 435 | 436 | for (vecSizeT i = 1; i < data.size(); ++i) { 437 | ret *= e[i]; 438 | } 439 | 440 | return ret; 441 | } 442 | 443 | /** 444 | * 判断当前矩阵是否是奇异矩阵 445 | * @author piratf 446 | * @return 1: 是奇异矩阵 0: 不是奇异矩阵 447 | */ 448 | template 449 | bool Matrix::isSingular() const { 450 | return det() ? false : true; 451 | } 452 | 453 | /** 454 | * 部分主元的高斯消去法求逆 455 | */ 456 | template 457 | Matrix Matrix::inv() const { 458 | #ifndef NOTEMPTY 459 | #define NOTEMPTY 460 | assert(!empty()); 461 | #endif 462 | #ifndef ISSQUARE 463 | #define ISSQUARE 464 | assert(isSquare()); 465 | #endif 466 | vecSizeT i, j, k, len = row(); 467 | double maxVal, temp; 468 | //将A矩阵存放在临时矩阵中 469 | Matrix TMat; 470 | 471 | if (SameType::isSame) { 472 | TMat = *this; 473 | } else { 474 | TMat = this ->toDouble(); 475 | } 476 | 477 | //初始化ans矩阵为单位阵 478 | Matrix ans = Matrix::eye(row(), col()); 479 | 480 | for (i = 0; i < len; i++) { 481 | //寻找主元 482 | maxVal = TMat[i][i]; 483 | k = i; 484 | 485 | for (j = i + 1; j < len; j++) { 486 | if (std::abs(TMat[j][i]) > std::abs(maxVal)) { 487 | maxVal = TMat[j][i]; 488 | k = j; 489 | } 490 | } 491 | 492 | //如果主元所在行不是第i行,进行行交换 493 | if (k != i) { 494 | TMat[i].swap(TMat[k]); 495 | ans[i].swap(ans[k]); 496 | } 497 | 498 | assert(cond2().real() < 1e11); 499 | //判断主元是否为0, 若是, 则矩阵A不是满秩矩阵,不存在逆矩阵 500 | // if (cond2().real() > 1e10) { 501 | // throw (Exception("ERROR** Matrix::inv -> there is no inverse matrix!")); 502 | // } 503 | //消去A的第i列除去i行以外的各行元素 504 | temp = TMat[i][i]; 505 | 506 | for (j = 0; j < len; j++) { 507 | TMat[i][j] = TMat[i][j] / temp; //主对角线上的元素变为1 508 | ans[i][j] = ans[i][j] / temp; //伴随计算 509 | } 510 | 511 | // 遍历行 512 | for (j = 0; j < len; j++) { 513 | // 不是第i行 514 | if (j != i) { 515 | temp = TMat[j][i]; 516 | 517 | // 第j行元素 - i行元素 * j列i行元素 518 | for (k = 0; k < len; k++) { 519 | TMat[j][k] -= TMat[i][k] * temp; 520 | ans[j][k] -= ans[i][k] * temp; 521 | } 522 | } 523 | } 524 | } 525 | 526 | return ans; 527 | } 528 | 529 | /** 530 | * 矩阵的行数 531 | */ 532 | template 533 | vecSizeT Matrix::row() const { 534 | return data.size(); 535 | } 536 | 537 | /** 538 | * 矩阵的列数 539 | */ 540 | template 541 | vecSizeT Matrix::col() const { 542 | if (data.size()) { 543 | return data[0].size(); 544 | } else { 545 | return 0; 546 | } 547 | } 548 | 549 | /** 550 | * 按行号取某一行,返回新的矩阵 551 | */ 552 | template 553 | Matrix Matrix::row(vecSizeT index) const { 554 | return Matrix(data[index]); 555 | } 556 | 557 | /** 558 | * 取矩阵中的某一行 559 | */ 560 | template 561 | std::vector &Matrix::operator [](vecSizeT index) { 562 | assert(index >= 0 && index < data.size()); 563 | return data[index]; 564 | } 565 | 566 | /** 567 | * 取矩阵中的某一行 568 | */ 569 | template 570 | const std::vector &Matrix::operator [](vecSizeT index) const { 571 | assert(index >= 0 && index < data.size()); 572 | return data[index]; 573 | } 574 | 575 | /** 576 | * 生成当前矩阵的 Hessenberg 形式,以新矩阵返回 577 | */ 578 | template 579 | Matrix Matrix::hess() const { 580 | #ifndef NOTEMPTY 581 | #define NOTEMPTY 582 | assert(!empty()); 583 | #endif 584 | #ifndef ISSQUARE 585 | #define ISSQUARE 586 | assert(isSquare()); 587 | #endif 588 | Matrix A = toDouble(); 589 | 590 | vecSizeT n = data.size(); 591 | vecSizeT i, j, k; 592 | Matrix ret(n, n); 593 | T temp = 0; 594 | vecSizeT max; 595 | 596 | for (k = 1; k < n - 1; ++k) { 597 | i = k - 1; 598 | max = k; 599 | temp = std::abs(A[k][i]); 600 | 601 | for (j = k + 1; j < n; ++j) { 602 | if (temp < std::abs(A[j][i])) { 603 | temp = std::abs(A[j][i]); 604 | max = j; 605 | } 606 | } 607 | 608 | ret[0][0] = A[max][i]; 609 | i = max; 610 | 611 | if (ret[0][0]) { 612 | if (i != k) { 613 | for (j = k - 1; j < n; ++j) { 614 | temp = A[i][j]; 615 | A[i][j] = A[k][j]; 616 | A[k][j] = temp; 617 | } 618 | 619 | for (j = 0; j < n; ++j) { 620 | temp = A[j][i]; 621 | A[j][i] = A[j][k]; 622 | A[j][k] = temp; 623 | } 624 | } 625 | 626 | for (i = k + 1; i < n; ++i) { 627 | temp = A[i][k - 1] / ret[0][0]; 628 | A[i][k - 1] = 0; 629 | 630 | for (vecSizeT j = k; j < n; ++j) { 631 | A[i][j] -= temp * A[k][j]; 632 | } 633 | 634 | for (j = 0; j < n; ++j) { 635 | A[j][k] += temp * A[j][i]; 636 | } 637 | } 638 | } 639 | } 640 | 641 | return A; 642 | } 643 | 644 | /** 645 | * 返回矩阵的全部特征根,以复数表示 646 | * QR 分解法 647 | */ 648 | template 649 | Matrix> Matrix::eig(double eps, unsigned LOOP) const { 650 | #ifndef NOTEMPTY 651 | #define NOTEMPTY 652 | assert(!empty()); 653 | #endif 654 | #ifndef ISSQUARE 655 | #define ISSQUARE 656 | assert(isSquare()); 657 | #endif 658 | unsigned loop = LOOP; 659 | const vecSizeT n = data.size(); 660 | vecSizeT m = n; 661 | Matrix A = hess(); 662 | Matrix ret(n, 2); 663 | vecSizeT i, j, k, t; 664 | double tempVar, indexVar, sign, p, q; 665 | double r, x, s, e, f, z, y, temp; 666 | double num; 667 | 668 | while (m != 0) { 669 | t = m - 1; 670 | 671 | while (t > 0) { 672 | temp = std::abs(A[t - 1][t - 1]); 673 | temp += std::abs(A[t][t]); 674 | temp *= eps; 675 | 676 | if (std::abs(A[t][t - 1]) > temp) { 677 | --t; 678 | } else { 679 | break; 680 | } 681 | } 682 | 683 | if (t == m - 1) { 684 | ret[m - 1][0] = A[m - 1][m - 1]; 685 | ret[m - 1][1] = 0; 686 | m -= 1; 687 | loop = LOOP; 688 | } else if (t == m - 2) { 689 | tempVar = -A[m - 1][m - 1] - A[m - 2][m - 2]; 690 | indexVar = A[m - 1][m - 1] * A[m - 2][m - 2] 691 | - A[m - 1][m - 2] * A[m - 2][m - 1]; 692 | num = tempVar * tempVar - 4 * indexVar; 693 | y = std::sqrt(std::abs(num)); 694 | 695 | if (num > 0) { 696 | sign = 1; 697 | 698 | if (tempVar < 0) { 699 | sign = -1; 700 | } 701 | 702 | ret[m - 1][0] = -(tempVar + sign * y) / 2; 703 | ret[m - 1][1] = 0; 704 | ret[m - 2][0] = indexVar / ret[m - 1][0]; 705 | ret[m - 2][1] = 0; 706 | } else { 707 | ret[m - 1][0] = -tempVar / 2; 708 | ret[m - 2][0] = -tempVar / 2; 709 | ret[m - 1][1] = y / 2; 710 | ret[m - 2][1] = -y / 2; 711 | } 712 | 713 | m -= 2; 714 | loop = LOOP; 715 | } else { 716 | if (loop < 1) { 717 | return Matrix >(); 718 | } 719 | 720 | --loop; 721 | j = t + 2; 722 | 723 | while (j < m) { 724 | A[j][j - 2] = 0; 725 | ++j; 726 | } 727 | 728 | j = t + 3; 729 | 730 | while (j < m) { 731 | A[j][j - 3] = 0; 732 | ++j; 733 | } 734 | 735 | k = t; 736 | 737 | while (k < m - 1) { 738 | if (k != t) { 739 | p = A[k][k - 1]; 740 | q = A[k + 1][k - 1]; 741 | 742 | if (k != m - 2) { 743 | r = A[k + 2][k - 1]; 744 | } else { 745 | r = 0; 746 | } 747 | } else { 748 | tempVar = A[m - 1][m - 1]; 749 | indexVar = A[m - 2][m - 2]; 750 | x = tempVar + indexVar; 751 | y = tempVar * indexVar - A[m - 2][m - 1] * A[m - 1][m - 2]; 752 | p = A[t][t] * (A[t][t] - x) + A[t][t + 1] * A[t + 1][t] + y; 753 | q = A[t + 1][t] * (A[t][t] + A[t + 1][t + 1] - x); 754 | r = A[t + 1][t] * A[t + 2][t + 1]; 755 | } 756 | 757 | if (p != 0 || q != 0 || r != 0) { 758 | if (p < 0) { 759 | sign = -1; 760 | } else { 761 | sign = 1; 762 | } 763 | 764 | s = sign * std::sqrt(p * p + q * q + r * r); 765 | 766 | if (k != t) { 767 | A[k][k - 1] = -s; 768 | } 769 | 770 | e = -q / s; 771 | f = -r / s; 772 | x = -p / s; 773 | y = -x - f * r / (p + s); 774 | num = e * r / (p + s); 775 | z = -x - e * q / (p + s); 776 | 777 | for (j = k; j < m; ++j) { 778 | tempVar = A[k][j]; 779 | indexVar = A[k + 1][j]; 780 | p = x * tempVar + e * indexVar; 781 | q = e * tempVar + y * indexVar; 782 | r = f * tempVar + num * indexVar; 783 | 784 | if (k != m - 2) { 785 | tempVar = A[k + 2][j]; 786 | p += f * tempVar; 787 | q += num * tempVar; 788 | r += z * tempVar; 789 | A[k + 2][j] = r; 790 | } 791 | 792 | A[k + 1][j] = q; 793 | A[k][j] = p; 794 | } 795 | 796 | j = k + 3; 797 | 798 | if (j > m - 2) { 799 | j = m - 1; 800 | } 801 | 802 | for (i = t; i < j + 1; ++i) { 803 | tempVar = A[i][k]; 804 | indexVar = A[i][k + 1]; 805 | p = x * tempVar + e * indexVar; 806 | q = e * tempVar + y * indexVar; 807 | r = f * tempVar + num * indexVar; 808 | 809 | if (k != m - 2) { 810 | tempVar = A[i][k + 2]; 811 | p += f * tempVar; 812 | q += num * tempVar; 813 | r += z * tempVar; 814 | A[i][k + 2] = r; 815 | } 816 | 817 | A[i][k + 1] = q; 818 | A[i][k] = p; 819 | } 820 | } 821 | 822 | ++k; 823 | } 824 | } 825 | } 826 | 827 | // 返回一个复数 828 | Matrix >res(n, 1); 829 | 830 | for (vecSizeT i = 0; i < ret.row(); ++i) { 831 | // 判断是否是复数类型 832 | bool flag = ComplexType::isComplex; 833 | 834 | if (flag) { 835 | res[i][0] = std::complex(static_cast >(ret[i][0]).real(), static_cast >(ret[i][1]).real()); 836 | } else { 837 | res[i][0] = std::complex(ret[i][0], ret[i][1]); 838 | } 839 | } 840 | 841 | return res; 842 | } 843 | 844 | /** 845 | * 返回矩阵中最大的元素 846 | */ 847 | template 848 | T Matrix::max() const { 849 | if (!data.size()) { 850 | return static_cast(0); 851 | } 852 | 853 | T maxv = data[0][0]; 854 | 855 | for (vecSizeT i = 0; i < data.size(); ++i) { 856 | for (vecSizeT j = 0; j < data[0].size(); ++j) { 857 | maxv = data[i][j] < maxv ? maxv : data[i][j]; 858 | } 859 | } 860 | 861 | return maxv; 862 | } 863 | 864 | /** 865 | * 返回矩阵中最小的元素 866 | */ 867 | template 868 | T Matrix::min() const { 869 | if (!data.size()) { 870 | return static_cast(0); 871 | } 872 | 873 | T minv = data[0][0]; 874 | 875 | for (vecSizeT i = 0; i < data.size(); ++i) { 876 | for (vecSizeT j = 0; j < data[0].size(); ++j) { 877 | minv = data[i][j] < minv ? data[i][j] : minv; 878 | } 879 | } 880 | 881 | return minv; 882 | } 883 | 884 | /** 885 | * 矩阵在 二范式 下的条件数 886 | */ 887 | template 888 | std::complex Matrix::cond2() const { 889 | // 获取特征值 890 | auto e = eig(); 891 | return e.max() / e.min(); 892 | } 893 | 894 | /** 895 | * 矩阵的均值 896 | */ 897 | template 898 | T Matrix::avg() const { 899 | if (!empty()) { 900 | return static_cast(0); 901 | } 902 | 903 | T sum = 0; 904 | 905 | for (vecSizeT i = 0; i < data.size(); ++i) { 906 | for (vecSizeT j = 0; j < data[0].size(); ++j) { 907 | sum += data[i][j]; 908 | } 909 | } 910 | 911 | // for (const auto row : data) { 912 | // for (T var : row) { 913 | // sum += var; 914 | // } 915 | // } 916 | return sum / (row() * col()); 917 | } 918 | 919 | /** 920 | * 矩阵相加赋值 921 | */ 922 | template 923 | Matrix Matrix::operator += (const Matrix &other) { 924 | #ifndef EQUALSIZE 925 | #define EQUALSIZE 926 | assert(data.size()); 927 | assert(row() == other.row() && col() == other.col()); 928 | #endif 929 | 930 | for (vecSizeT i = 0; i < row(); ++i) { 931 | for (vecSizeT j = 0; j < col(); ++j) { 932 | data[i][j] += other[i][j]; 933 | } 934 | } 935 | 936 | return *this; 937 | } 938 | 939 | /** 940 | * 矩阵相加 941 | */ 942 | template 943 | Matrix Matrix::operator + (const Matrix &other) const { 944 | #ifndef EQUALSIZE 945 | #define EQUALSIZE 946 | assert(data.size()); 947 | assert(row() == other.row() && col() == other.col()); 948 | #endif 949 | 950 | Matrix ret(row(), col()); 951 | 952 | for (vecSizeT i = 0; i < row(); ++i) { 953 | for (vecSizeT j = 0; j < col(); ++j) { 954 | ret[i][j] = data[i][j] + other[i][j]; 955 | } 956 | } 957 | 958 | return ret; 959 | } 960 | 961 | 962 | /** 963 | * 矩阵相减 964 | */ 965 | template 966 | Matrix Matrix::operator -= (const Matrix &other) { 967 | #ifndef EQUALSIZE 968 | #define EQUALSIZE 969 | assert(data.size()); 970 | assert(row() == other.row() && col() == other.col()); 971 | #endif 972 | 973 | for (vecSizeT i = 0; i < row(); ++i) { 974 | for (vecSizeT j = 0; j < col(); ++j) { 975 | data[i][j] -= other[i][j]; 976 | } 977 | } 978 | 979 | return *this; 980 | } 981 | 982 | /** 983 | * 矩阵相减 984 | */ 985 | template 986 | Matrix Matrix::operator - (const Matrix &other) const { 987 | #ifndef EQUALSIZE 988 | #define EQUALSIZE 989 | assert(data.size()); 990 | assert(row() == other.row() && col() == other.col()); 991 | #endif 992 | 993 | Matrix ret(row(), col()); 994 | 995 | for (vecSizeT i = 0; i < row(); ++i) { 996 | for (vecSizeT j = 0; j < col(); ++j) { 997 | ret[i][j] = data[i][j] - other[i][j]; 998 | } 999 | } 1000 | 1001 | return ret; 1002 | } 1003 | 1004 | /** 1005 | * 矩阵相乘 1006 | * 普通算法 1007 | */ 1008 | template 1009 | void Matrix::mul(Matrix &ret, const Matrix &other) const { 1010 | #ifndef MULCHECK 1011 | #define MULCHECK 1012 | assert(data.size()); 1013 | assert(col() == other.row()); 1014 | #endif 1015 | 1016 | for (vecSizeT i = 0; i < row(); ++i) { 1017 | for (vecSizeT k = 0; k < col(); ++k) { 1018 | for (vecSizeT j = 0; j < col(); ++j) { 1019 | ret[i][j] += data[i][k] * other[k][j]; 1020 | } 1021 | } 1022 | } 1023 | 1024 | return; 1025 | } 1026 | 1027 | /** 1028 | * 矩阵相乘 1029 | * 普通算法 1030 | */ 1031 | template 1032 | Matrix Matrix::operator * (const Matrix &other) const { 1033 | #ifndef MULCHECK 1034 | #define MULCHECK 1035 | assert(data.size()); 1036 | assert(col() == other.row()); 1037 | #endif 1038 | Matrix ret(col(), other.row()); 1039 | 1040 | // 对称矩阵使用 斯特拉森乘法 1041 | if (row() == col()) { 1042 | smul(ret, other); 1043 | } else { 1044 | // 普通乘法 1045 | mul(ret, other); 1046 | } 1047 | 1048 | return ret; 1049 | } 1050 | 1051 | /** 1052 | * 矩阵 *= 1053 | * 普通算法 1054 | */ 1055 | template 1056 | Matrix Matrix::operator *= (const Matrix &other) { 1057 | #ifndef MULCHECK 1058 | #define MULCHECK 1059 | assert(data.size()); 1060 | assert(col() == other.row()); 1061 | #endif 1062 | Matrix ret(col(), other.row()); 1063 | 1064 | // 大的对称矩阵使用 斯特拉森乘法 1065 | if (row() > 50 && row() == col()) { 1066 | smul(ret, other); 1067 | } else { 1068 | // 普通乘法 1069 | mul(ret, other); 1070 | } 1071 | 1072 | return ret; 1073 | } 1074 | 1075 | /** 1076 | * 矩阵左除 1077 | */ 1078 | template 1079 | Matrix Matrix::div(const Matrix &other) const { 1080 | #ifndef DIVCHECK 1081 | #define DIVCHECK 1082 | assert(data.size()); 1083 | assert(other.row() == other.col()); 1084 | #endif 1085 | 1086 | return this ->toDouble() * other.inv(); 1087 | } 1088 | /** 1089 | * 矩阵右除 1090 | */ 1091 | template 1092 | Matrix Matrix::rdiv(const Matrix &other) const { 1093 | #ifndef DIVCHECK 1094 | #define DIVCHECK 1095 | assert(data.size()); 1096 | assert(other.row() == other.col()); 1097 | #endif 1098 | 1099 | return this ->inv() * other.toDouble(); 1100 | } 1101 | 1102 | /** 1103 | * 矩阵相除 1104 | * 左除 1105 | */ 1106 | template 1107 | Matrix Matrix::operator / (const Matrix &other) const { 1108 | #ifndef DIVCHECK 1109 | #define DIVCHECK 1110 | assert(data.size()); 1111 | assert(other.row() == other.col()); 1112 | #endif 1113 | 1114 | return div(other); 1115 | } 1116 | 1117 | /** 1118 | * 矩阵相除 1119 | * 左除 1120 | */ 1121 | template 1122 | Matrix Matrix::operator /= (const Matrix &other) { 1123 | #ifndef DIVCHECK 1124 | #define DIVCHECK 1125 | assert(data.size()); 1126 | assert(other.row() == other.col()); 1127 | #endif 1128 | 1129 | return *this = div(other); 1130 | } 1131 | 1132 | /** 1133 | * 矩阵相除 1134 | * 右除 1135 | */ 1136 | template 1137 | Matrix Matrix::operator % (const Matrix &other) const { 1138 | #ifndef DIVCHECK 1139 | #define DIVCHECK 1140 | assert(data.size()); 1141 | assert(other.row() == other.col()); 1142 | #endif 1143 | 1144 | return rdiv(other); 1145 | } 1146 | 1147 | /** 1148 | * 转换为 double 矩阵 1149 | */ 1150 | template 1151 | Matrix Matrix::toDouble() const { 1152 | Matrix mat(row(), col()); 1153 | 1154 | // 如果矩阵是复数,则只取实数部分,忽略虚数部分 1155 | // 未实现 1156 | for (vecSizeT i = 0; i < row(); ++i) { 1157 | for (vecSizeT j = 0; j < col(); ++j) { 1158 | mat[i][j] = static_cast(data[i][j]); 1159 | } 1160 | } 1161 | 1162 | return mat; 1163 | } 1164 | 1165 | /** 1166 | * 斯特拉森乘法主函数,需要两个 n * n 矩阵 1167 | */ 1168 | template 1169 | void Matrix::smul(Matrix &ret, const Matrix &other) const { 1170 | #ifndef MULCHECK 1171 | #define MULCHECK 1172 | assert(data.size()); 1173 | assert(col() == other.row()); 1174 | #endif 1175 | #ifndef ISSQUARE 1176 | #define ISSQUARE 1177 | assert(isSquare()); 1178 | #endif 1179 | #ifndef OTHERISSQUARE 1180 | #define OTHERISSQUARE 1181 | assert(other.isSquare()); 1182 | #endif 1183 | vecSizeT n = row(); 1184 | StrassenMul(0, n, 0, n, other, ret); 1185 | } 1186 | 1187 | /** 1188 | * 斯特拉森乘法,复杂度 n ^ 2.80 1189 | */ 1190 | template 1191 | void Matrix::StrassenMul(vecSizeT rs, vecSizeT re, vecSizeT cs, vecSizeT ce, const Matrix &other, Matrix &ret) const { 1192 | #ifndef MULCHECK 1193 | #define MULCHECK 1194 | assert(data.size()); 1195 | assert(col() == other.row()); 1196 | #endif 1197 | 1198 | if (re - rs == 2 && ce - cs == 2) { 1199 | vecSizeT rs1 = rs + 1; 1200 | vecSizeT cs1 = cs + 1; 1201 | T P1 = data[rs][cs] * (other[rs][cs1] - other[rs1][cs1]); 1202 | T P2 = (data[rs][cs] + data[rs][cs1]) * other[rs1][cs1]; 1203 | T P3 = (data[rs1][cs] + data[rs1][cs1]) * other[rs][cs]; 1204 | T P4 = data[rs1][cs1] * (other[rs1][cs] - other[rs][cs]); 1205 | T P5 = (data[rs][cs] + data[rs1][cs1]) * (other[rs][cs] + other[rs1][cs1]); 1206 | T P6 = (data[rs][cs1] - data[rs1][cs1]) * (other[rs1][cs] + other[rs1][cs1]); 1207 | T P7 = (data[rs][cs] - data[rs1][cs]) * (other[rs][cs] + other[rs][cs1]); 1208 | ret[rs][cs] = P5 + P4 - P2 + P6; 1209 | ret[rs][cs1] = P1 + P2; 1210 | ret[rs1][cs] = P3 + P4; 1211 | ret[rs1][cs1] = P1 + P5 - P3 - P7; 1212 | } else if (re - rs < 2 || rs - rs < 2) { 1213 | for (vecSizeT i = rs; i < re; ++i) { 1214 | for (vecSizeT k = cs; k < ce; ++k) { 1215 | for (vecSizeT j = cs; j < ce; ++j) { 1216 | ret[i][j] += data[i][k] * other[k][j]; 1217 | } 1218 | } 1219 | } 1220 | } else { 1221 | vecSizeT rm = rs + ((re - rs) / 2); 1222 | vecSizeT cm = cs + ((ce - cs) / 2); 1223 | StrassenMul(rs, rm, cs, cm, other, ret); 1224 | StrassenMul(rm, re, cs, cm, other, ret); 1225 | StrassenMul(rs, rm, cm, ce, other, ret); 1226 | StrassenMul(rm, re, cm, ce, other, ret); 1227 | } 1228 | } 1229 | 1230 | /** 1231 | * 从矩阵中取一部分 1232 | * 从 0 开始,到 re 结束 1233 | * 返回新的另一个矩阵,不影响原矩阵 1234 | */ 1235 | template 1236 | Matrix Matrix::cut(vecSizeT rs, vecSizeT re, vecSizeT cs, vecSizeT ce) const { 1237 | #ifndef NOTEMPTY 1238 | #define NOTEMPTY 1239 | assert(!empty()); 1240 | #endif 1241 | assert(re < row() && rs >= 0 && ce < col() && cs >= 0); 1242 | Matrix ret((re + 1) - rs, (ce + 1) - cs); 1243 | 1244 | for (vecSizeT i = rs, ri = 0; i <= re; ++i, ++ri) { 1245 | for (vecSizeT j = cs, rj = 0; j <= ce; ++j, ++rj) { 1246 | ret[ri][rj] = data[i][j]; 1247 | } 1248 | } 1249 | 1250 | return ret; 1251 | } 1252 | 1253 | /** 1254 | * 矩阵清空 1255 | */ 1256 | template 1257 | void Matrix::clear() { 1258 | data.clear(); 1259 | } 1260 | 1261 | /** 1262 | * 矩阵清零 1263 | */ 1264 | template 1265 | void Matrix::setZero() { 1266 | vecSizeT n = row(); 1267 | vecSizeT m = col(); 1268 | 1269 | for (vecSizeT i = 0; i < n; ++i) { 1270 | std::memset(&data[i][0], 0, sizeof(T) * m); 1271 | } 1272 | } 1273 | 1274 | /** 1275 | * 拷贝矩阵 1276 | */ 1277 | template 1278 | Matrix Matrix::operator = (const Matrix &other) { 1279 | data = other.getData(); 1280 | return *this; 1281 | } 1282 | 1283 | /** 1284 | * 移动矩阵 1285 | */ 1286 | template 1287 | Matrix Matrix::operator = (Matrix &&other) { 1288 | data.swap(other.getData()); 1289 | return *this; 1290 | } 1291 | 1292 | /** 1293 | * 获取 data 成员,可用于整块更新 1294 | */ 1295 | template 1296 | std::vector > &Matrix::getData() { 1297 | return data; 1298 | } 1299 | 1300 | /** 1301 | * 以 const 方式获取成员,可用于安全读 1302 | */ 1303 | template 1304 | const std::vector > &Matrix::getData() const { 1305 | return data; 1306 | } 1307 | 1308 | /** 1309 | * 生成 0 - 1 之间的一个正态随机数 1310 | */ 1311 | template 1312 | T Matrix::randn() { 1313 | setRand(); 1314 | return normDis(*_genPtr); 1315 | } 1316 | 1317 | /** 1318 | * 生成一个 n * n 正态随机矩阵 1319 | * 输入参数为矩阵的边长 1320 | */ 1321 | template 1322 | Matrix Matrix::randn(vecSizeT n) { 1323 | setRand(); 1324 | Matrix mat(n, n); 1325 | 1326 | for (vecSizeT i = 0; i < n; ++i) { 1327 | for (vecSizeT j = 0; j < n; ++j) { 1328 | mat[i][j] = normDis(*_genPtr); 1329 | } 1330 | } 1331 | 1332 | return mat; 1333 | } 1334 | 1335 | /** 1336 | * 生成一个正态随机矩阵 1337 | * 输入参数为矩阵的行数和列数 1338 | */ 1339 | template 1340 | Matrix Matrix::randn(vecSizeT r, vecSizeT c) { 1341 | setRand(); 1342 | Matrix mat(r, c); 1343 | auto fun = std::bind(normDis, *_genPtr); 1344 | 1345 | for (vecSizeT i = 0; i < r; ++i) { 1346 | for (vecSizeT j = 0; j < c; ++j) { 1347 | mat[i][j] = normDis(*_genPtr); 1348 | } 1349 | } 1350 | 1351 | return mat; 1352 | } 1353 | 1354 | /** 1355 | * 初始化单例随机数生成器 1356 | */ 1357 | template 1358 | void Matrix::setRand() { 1359 | if (!_genPtr) { 1360 | #ifdef linux 1361 | std::random_device rd; 1362 | _genPtr = new std::mt19937(rd()); 1363 | #else 1364 | _genPtr = new std::mt19937(std::time(NULL)); 1365 | #endif 1366 | } 1367 | } 1368 | 1369 | /** 1370 | * 传入初始化单例随机数生成器 1371 | */ 1372 | template 1373 | void Matrix::setRand(std::mt19937 *_p) { 1374 | if (_genPtr) { 1375 | delete _genPtr; 1376 | } 1377 | 1378 | _genPtr = _p; 1379 | } 1380 | 1381 | /** 1382 | * 如果矩阵是浮点数,生成 0 - 1 之间的一个均匀分布随机数 1383 | * 如果矩阵是整形,生成 0 - 65525 之间的一个均匀分布随机数 1384 | */ 1385 | template 1386 | T Matrix::rand() { 1387 | setRand(); 1388 | 1389 | if (SameType::isSame) { 1390 | return unifDoubleDis(*_genPtr); 1391 | } else if (SameType::isSame) { 1392 | return unifFloatDis(*_genPtr); 1393 | } else { 1394 | return unifIntDis(*_genPtr); 1395 | } 1396 | } 1397 | 1398 | /** 1399 | * 生成一个 n * n 均匀分布随机矩阵 1400 | * 输入参数为矩阵的边长 1401 | */ 1402 | template 1403 | Matrix Matrix::rand(vecSizeT n) { 1404 | setRand(); 1405 | Matrix mat(n, n); 1406 | 1407 | for (vecSizeT i = 0; i < n; ++i) { 1408 | for (vecSizeT j = 0; j < n; ++j) { 1409 | mat[i][j] = rand(); 1410 | } 1411 | } 1412 | 1413 | return mat; 1414 | } 1415 | 1416 | /** 1417 | * 生成一个均匀分布随机矩阵 1418 | * 输入参数为矩阵的行数和列数 1419 | */ 1420 | template 1421 | Matrix Matrix::rand(vecSizeT r, vecSizeT c) { 1422 | setRand(); 1423 | Matrix mat(r, c); 1424 | 1425 | for (vecSizeT i = 0; i < r; ++i) { 1426 | for (vecSizeT j = 0; j < c; ++j) { 1427 | mat[i][j] = rand(); 1428 | } 1429 | } 1430 | 1431 | return mat; 1432 | } 1433 | 1434 | } 1435 | 1436 | namespace pmh = piratfMatrixH; 1437 | 1438 | #endif --------------------------------------------------------------------------------