├── LICENSE ├── README.md ├── performance_tests └── container_comparison │ ├── Makefile │ ├── container │ ├── container.cpp │ ├── dcontainer │ ├── dcontainer.cpp │ ├── scontainer │ └── scontainer.cpp ├── tensor ├── mapper.hpp ├── tensor.hpp ├── tensor_addition.hpp ├── tensor_container.hpp ├── tensor_dynamic_cpu.hpp ├── tensor_expression_dynamic_cpu.hpp ├── tensor_expression_interface.hpp ├── tensor_expression_static_cpu.hpp ├── tensor_expressions.hpp ├── tensor_operations.hpp ├── tensor_static_cpu.hpp ├── tensor_subtraction.hpp └── tensor_traits.hpp └── tests ├── Makefile ├── container_tests.cpp ├── operations_tests.cpp ├── tensor_tests.cpp ├── tests.cpp └── traits_tests.cpp /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *A fast c++ tensor library* 2 | 3 | # Tensor 4 | 5 | Tensor is a c++ tensor expression library. It is designed with both speed and clarity of expression in mind. It it thus intended to provide high levels of performance but allow operations on tensors in the code to appear exactly as they do mathematically. 6 | 7 | [Template metaprogramming](https://en.wikipedia.org/wiki/Template_metaprogramming) is used to 'offload' any work which can be computed at compile time, to the compiler and [expression templates](https://en.wikipedia.org/wiki/Expression_templates) are used to achieve the translation of the mathematically expressed code to high performance code. 8 | 9 | Tests have been written using the [Boost Test library](http://www.boost.org/doc/libs/1_58_0/libs/test/doc/html/index.html) to verify the 'correctness' of all the implemented components. The tests also help to illustrate the usage of the various components of the library. 10 | 11 | The long term goal is to develop something along the lines of the tensor library in the python theano libray, 12 | but with support for any rank tensors with both CPU and GPU functionality. 13 | 14 | # Documentation 15 | 16 | Please see [Tensor Documentation](http://robclu.github.io/tensor/) for documentation and usage examples. 17 | 18 | # Current Status 19 | 20 | Currently the library is CPU only and is single-threaded as the development process has just begun. However, the library will be extended to include GPU functionality (with CUDA and probably also OpenCL) and multi-threading (and therefore multi-core CPU - probably with OpenMP and MPI). 21 | 22 | There is quite a lot of functionality which is working at present, however, the first 23 | iteration of the development used vectors as the data containers. I feel that a lot of performance improvement 24 | can be achieved by using static containers and the properties of the tensor which come with knowing the sizes 25 | of the dimensions when the tensor is created. 26 | 27 | I did some tests with comparing static vs dynamic tensors and the static tensors were up to 20x faster than dynamic tensors, and even faster than ```std::array``` for element access as the static tensors do the mapping using the dimension sizes at compile time. 28 | 29 | I thus decided to completely redesign the interface, allowing a selection between the static and dynamic tensors, as well as a selection between CPU and GPU implementations. 30 | 31 | # Dependencies 32 | 33 | * [nano](https://github.com/robclu/nano) : A template metaprogramming library, is used to offload some of the work to the compiler, for example things like index mapping for slicing and multiplication. 34 | * [boost unit](http://www.boost.org/doc/libs/1_58_0/libs/test/doc/html/index.html) : For the unit testing 35 | component of the library. This is not necessary of you aren't running the tests. 36 | 37 | # Building 38 | 39 | ## Nano 40 | 41 | You can get the nano library from here - [nano](https://github.com/robclu/nano) - it is a header only 42 | library. By default it is installed to ```usr/include```. If you install it somewhere else make sure that it 43 | is on your path so that ```tensor``` can find it. 44 | 45 | ## Boost 46 | 47 | You can get the Boost test library from here - [Boost](http://www.boost.org/) - and follow the [Getting Started Guide](http://www.boost.org/doc/libs/1_59_0/more/getting_started/index.html) to install the libraries. 48 | 49 | __Note:__ You only need the test library, but it is dynamically linked in the tensor tests provided with the ```tensor``` library, so you should install it to allow dynamic linking (i.e install the test library and not just the ```.hpp``` file.) 50 | 51 | ## CUDA 52 | 53 | GPU functionality is not currently implemented so nothing to be done here. 54 | 55 | # Compiling 56 | 57 | Tensor has been tested with the following compilers 58 | 59 | * g++ (4.9.1) 60 | * clang++ (3.6.1) 61 | 62 | Since tensor is (currently) a header-only library, there is nothing to install if you would just like to use it in your own application. However, tests are provided with tensor so ensure that everything is working as expected as well as to provide examples of the usage of tensor. 63 | 64 | To compile the tests, cd into ```tests/```, at which point you are provided with a few options: 65 | 66 | * Make all the tests 67 | * Make an individual tests 68 | 69 | ## All tests 70 | 71 | To make all the tests, simply issue 72 | ``` 73 | make all (or make -jN all -- to make in parallel with N processes) 74 | ``` 75 | 76 | ## Individual tests 77 | 78 | The following individual test components are provided 79 | 80 | * __tensor__ : tests related to tensors specifically 81 | * __traits__ : tests for the tensor traits 82 | * __container__ : tests for the tensor containers 83 | * __operations__ : tests for the operations (addition, subtraction etc...) 84 | 85 | To make an individual tests, issuse 86 | 87 | ``` 88 | make 89 | ``` 90 | 91 | with the appropriate test name, for example ```make container``` 92 | 93 | ## Cleaning 94 | 95 | To clean the tests, issue 96 | 97 | ``` 98 | make clean 99 | ``` 100 | -------------------------------------------------------------------------------- /performance_tests/container_comparison/Makefile: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # EXECUTABLE NAME # 3 | ######################################################################################## 4 | 5 | EXE_SCONT := scontainer 6 | EXE_DCONT := dcontainer 7 | EXE_CONT := container 8 | 9 | ######################################################################################## 10 | # INPUT FILES # 11 | ######################################################################################## 12 | 13 | INPUTS := 14 | OBJS := 15 | 16 | ######################################################################################## 17 | # COMPILERS # 18 | # # 19 | # NOTE: Compiling with cuda because GPU support will be added # 20 | ######################################################################################## 21 | 22 | CXX := g++ 23 | 24 | ######################################################################################## 25 | # INCLUDE DIRECTORIES # 26 | ######################################################################################## 27 | 28 | CXX_INC := 29 | 30 | ######################################################################################## 31 | # LIBRARIES # 32 | ######################################################################################## 33 | 34 | CXX_LIBS := 35 | CXX_LDIR := 36 | 37 | ######################################################################################## 38 | # COMPILER FLAGS # 39 | # # 40 | # NOTE: To enable compiler warnings, remove -w and replace with : # 41 | # --compiler-options -Wall # 42 | ######################################################################################## 43 | 44 | CXX_FLAGS := -std=c++11 -w -O3 45 | 46 | ######################################################################################## 47 | # TARGET RULES # 48 | ####################################################################################### 49 | 50 | .PHONY: scont scont_asm dcont dcont_asm cont clean 51 | 52 | scont: build_and_run_scont 53 | dcont: build_and_run_dcont 54 | cont: build_and_run_cont 55 | 56 | build_and_run_scont: build_scont 57 | rm -rf *.o 58 | ./$(EXE_SCONT) 59 | 60 | scontainer.o: scontainer.cpp 61 | $(CXX) $(CXX_INC) $(CXX_FLAGS) -o $@ -c $< 62 | 63 | build_scont: scontainer.o 64 | $(CXX) -o $(EXE_SCONT) $+ $(CXX_LDIR) $(CXX_LIBS) 65 | 66 | scontainer.s: scontainer.cpp 67 | $(CXX) $(CXX_INC) $(CXX_FLAGS) -o $@ -c $< 68 | 69 | scont_asm: CXX_FLAGS += -S -g -fverbose-asm -masm=intel -O3 70 | scont_asm: scontainer.s 71 | as -adhln scontainer.s > scontainer.lst 72 | 73 | build_and_run_dcont: build_dcont 74 | rm -rf *.o 75 | ./$(EXE_DCONT) 76 | 77 | dcontainer.o: dcontainer.cpp 78 | $(CXX) $(CXX_INC) $(CXX_FLAGS) -o $@ -c $< 79 | 80 | build_dcont: dcontainer.o 81 | $(CXX) -o $(EXE_DCONT) $+ $(CXX_LDIR) $(CXX_LIBS) 82 | 83 | dcontainer.s: dcontainer.cpp 84 | $(CXX) $(CXX_INC) $(CXX_FLAGS) -o $@ -c $< 85 | 86 | dcont_asm: CXX_FLAGS += -S -g -fverbose-asm -masm=intel -O3 87 | dcont_asm: dcontainer.s 88 | as -adhln dcontainer.s > dcontainer.lst 89 | 90 | build_and_run_cont: build_cont 91 | rm -rf *.o 92 | ./$(EXE_CONT) 93 | 94 | container.o: container.cpp 95 | $(CXX) $(CXX_INC) $(CXX_FLAGS) -o $@ -c $< 96 | 97 | build_cont: container.o 98 | $(CXX) -o $(EXE_CONT) $+ $(CXX_LDIR) $(CXX_LIBS) 99 | 100 | clean: 101 | rm -rf *.o 102 | rm -rf *.s 103 | rm -rf *.lst 104 | rm -rf $(EXE_SCONT) 105 | rm -rf $(EXE_DCONT) 106 | rm -rf $(EXE_CONT) 107 | 108 | -------------------------------------------------------------------------------- /performance_tests/container_comparison/container: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robclu/tensor/52da3491984b60cc2559fb4cc9a4f7f2bcfc396c/performance_tests/container_comparison/container -------------------------------------------------------------------------------- /performance_tests/container_comparison/container.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using std::array; 5 | using std::cout; 6 | 7 | constexpr size_t D1 = 200; 8 | constexpr size_t D2 = 3000; 9 | 10 | int main(int argc, char** argv) 11 | { 12 | array container; 13 | size_t offset = 0; 14 | 15 | for (size_t i = 0; i < D1; ++i) 16 | for (size_t j = 0; j < D2; ++j) 17 | offset = container[i * D1 + j]; 18 | 19 | std::cout << offset; 20 | } 21 | -------------------------------------------------------------------------------- /performance_tests/container_comparison/dcontainer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robclu/tensor/52da3491984b60cc2559fb4cc9a4f7f2bcfc396c/performance_tests/container_comparison/dcontainer -------------------------------------------------------------------------------- /performance_tests/container_comparison/dcontainer.cpp: -------------------------------------------------------------------------------- 1 | #include "../../tensor/container_mapper.hpp" 2 | #include 3 | 4 | constexpr size_t D1 = 200; 5 | constexpr size_t D2 = 3000; 6 | constexpr size_t D3 = 7; 7 | constexpr size_t D4 = 2; 8 | constexpr size_t D5 = 2; 9 | constexpr size_t D6 = 12; 10 | 11 | int main(int argc, char** argv) 12 | { 13 | 14 | std::vector dim_sizes{ D1, D2, D3, D4, D5, D6 }; 15 | size_t offset = 0; 16 | 17 | for (size_t i = 0; i < D1; ++i) 18 | for (size_t j = 0; j < D2; ++j) 19 | offset = ftl::dynamic_mapper::indices_to_index(dim_sizes, i, j, 2, 0, 1, 8); 20 | 21 | std::cout << offset; 22 | } 23 | -------------------------------------------------------------------------------- /performance_tests/container_comparison/scontainer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robclu/tensor/52da3491984b60cc2559fb4cc9a4f7f2bcfc396c/performance_tests/container_comparison/scontainer -------------------------------------------------------------------------------- /performance_tests/container_comparison/scontainer.cpp: -------------------------------------------------------------------------------- 1 | #include "../../tensor/container_mapper.hpp" 2 | #include "../../tensor/tensor.h" 3 | 4 | constexpr size_t D1 = 200; 5 | constexpr size_t D2 = 3000; 6 | constexpr size_t D3 = 7; 7 | constexpr size_t D4 = 20; 8 | constexpr size_t D5 = 2; 9 | constexpr size_t D6 = 12; 10 | 11 | int main(int argc, char** argv) 12 | { 13 | // Define sype for static tensor 14 | using static_type = ftl::stensor; // Static tensor type 15 | using dim_sizes = static_type::data_container::dimension_sizes; // dim sizes of static tensor 16 | 17 | static_type s; 18 | 19 | size_t offset = 0; 20 | 21 | for (size_t i = 0; i < D1; ++i) 22 | for (size_t j = 0; j < D2; ++j) 23 | offset = ftl::static_mapper::indices_to_index(i, j, 2, 0, 1, 8); 24 | 25 | std::cout << offset; 26 | } 27 | -------------------------------------------------------------------------------- /tensor/mapper.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for mapper related classes and variables for mapping linear indices to multiple 3 | /// dimensions and from mapping multiple dimensions to a linear index etc for both static and dynamic 4 | /// containers 5 | // ---------------------------------------------------------------------------------------------------------- 6 | 7 | /* 8 | * ---------------------------------------------------------------------------------------------------------- 9 | * Header file for mapper class 10 | * Copyright (C) 2015 Rob Clucas robclu1818@gmail.com 11 | * 12 | * This program is free software; you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published 14 | * by the Free Software Foundation; either version 2 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License along 23 | * with this program; if not, write to the Free Software Foundation, 24 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 25 | * ---------------------------------------------------------------------------------------------------------- 26 | */ 27 | 28 | #ifndef FTL_MAPPER_HPP 29 | #define FTL_MAPPER_HPP 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | namespace ftl { 38 | 39 | namespace detail { 40 | 41 | // ---------------------------------------------------------------------------------------------------------- 42 | /// @struct MapToIndexStatic 43 | /// @brief Takes a list of indices and a list of dimension sizes, and determines the offset of an 44 | /// element given by the indices, in contiguous memory 45 | /// @tparam DimSizes The sizes of each of the dimensions 46 | /// @tparam Indices The value of the element in each of the indices 47 | // ---------------------------------------------------------------------------------------------------------- 48 | template 49 | struct MapToIndexStatic; 50 | 51 | // Recursive case 52 | template 53 | struct MapToIndexStatic 54 | { 55 | // On each iteration the product of the size of all previous dimensions must be calculated 56 | // to determine the memory offset of this dimension, so determine the stopping index 57 | using end_index = typename std::conditional< 58 | DimSizes::size - sizeof...(IR) == 1 , 59 | typename nano::size_t<0> , 60 | typename nano::size_t>::type; 61 | 62 | // The product sum of the previous dimensions (previous iterations) so if we are on iteration 63 | // 3 then this is the product of the size of dimension 0 and 1 64 | static constexpr size_t dim_product_sum = nano::accumulate::result; 65 | 66 | // The offset calculation 67 | static constexpr size_t offset(size_t current_offset, IF&& index_first, IR&&... indices_rest) 68 | { 69 | // Recursively call until the terminating case 70 | // If first iteration use index_first as offset 71 | // if other iteration, add mult with prev products 72 | return DimSizes::size - sizeof...(IR) == 1 73 | ? MapToIndexStatic::offset(current_offset + index_first , 74 | std::forward(indices_rest)... ) 75 | : MapToIndexStatic::offset(current_offset + index_first * dim_product_sum, 76 | std::forward(indices_rest)... ); 77 | } 78 | }; 79 | 80 | // Terminating (base) case 81 | template 82 | struct MapToIndexStatic 83 | { 84 | // Just need to return the result here 85 | static constexpr size_t offset(size_t current_offset) { return current_offset; } 86 | }; 87 | 88 | // Dynamic implementation 89 | template 90 | size_t MapToIndexDynamic(const Container& dim_sizes , 91 | size_t current_offset ) 92 | { 93 | return current_offset; 94 | } 95 | 96 | template 97 | size_t MapToIndexDynamic(const Container& dim_sizes , 98 | size_t current_offset , 99 | IF index_first , 100 | IR... indices_rest ) 101 | { 102 | size_t num_indices = sizeof...(IR); 103 | current_offset += std::accumulate(dim_sizes.begin() , 104 | dim_sizes.end() - num_indices - 1 , 105 | 1 , 106 | std::multiplies() ) * index_first; 107 | // Keep iterating 108 | return MapToIndexDynamic(dim_sizes, current_offset, indices_rest...); 109 | } 110 | 111 | } // End namespace detail 112 | 113 | // ---------------------------------------------------------------------------------------------------------- 114 | /// @struct StaticMapper 115 | /// @brief Interface which provides static mapping (uses TMP to determine some of the mapping variables 116 | /// at compile time for improved performance) from indices to a single offset index and from an 117 | /// index offset to a list of indices 118 | // ---------------------------------------------------------------------------------------------------------- 119 | struct StaticMapper { 120 | 121 | // ---------------------------------------------------------------------------------------------------------- 122 | /// @brief Maps any number of indices which represent the location of an index in a multi-dimensional 123 | /// space, to a singe index offset in the contiguous memory which is representing that 124 | /// multi-dimensional space 125 | /// @param[in] index_first The index of the element in the first dimension 126 | /// @param[in] indices_rest The indices of the element in the other dimensions 127 | /// @tparam DimSizes The list of dimension sizes for the multi-dimensional space 128 | /// @tparam IF The type of index_first 129 | /// @tparam IR The types of indices_rest 130 | // ---------------------------------------------------------------------------------------------------------- 131 | template 132 | static constexpr size_t indices_to_index(IF&& index_first, IR&&... indices_rest) 133 | { 134 | return detail::MapToIndexStatic::offset(0 , 135 | std::forward(index_first) , 136 | std::forward(indices_rest)... ); 137 | } 138 | 139 | }; 140 | 141 | struct DynamicMapper { 142 | 143 | template 144 | static size_t indices_to_index(const Container& dim_sizes , 145 | IF index_first , 146 | IR... indices_rest) 147 | { 148 | return detail::MapToIndexDynamic<1>(dim_sizes, index_first, indices_rest...); 149 | } 150 | 151 | }; 152 | 153 | } // End namespace ftl 154 | #endif // FTL_MAPPER_HPP 155 | -------------------------------------------------------------------------------- /tensor/tensor.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor interface for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_HPP 24 | #define FTL_TENSOR_HPP 25 | 26 | //#include "tensor_expressions.hpp" 27 | #include "tensor_dynamic_cpu.hpp" 28 | #include "tensor_static_cpu.hpp" 29 | 30 | namespace ftl { 31 | 32 | // Define a type alias for a general tensor that will 'choose' the specialization 33 | template 34 | using Tensor = TensorInterface>; 35 | 36 | } // End namespace ftl 37 | #endif // FTL_TENSOR_INTERFACE_HPP 38 | -------------------------------------------------------------------------------- /tensor/tensor_addition.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor addition for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_ADDITION_HPP 24 | #define FTL_TENSOR_ADDITION_HPP 25 | 26 | #include "tensor_expressions.hpp" 27 | 28 | namespace ftl { 29 | 30 | // ---------------------------------------------------------------------------------------------------------- 31 | /// @class TensorAddition 32 | /// @brief Expression class for calculating the addition of two tensors. 33 | /// @tparam E1 The first expression for addition 34 | /// @tparam E2 The second expression for addition 35 | /// @tparam T1 The traits of the first expression 36 | /// @tparam T2 The traits if the second expression 37 | // ---------------------------------------------------------------------------------------------------------- 38 | template 39 | class TensorAddition : public TensorExpression, T1> { 40 | public: 41 | using traits = T1; 42 | using dim_container = typename traits::dim_container; 43 | using size_type = typename traits::size_type; 44 | using data_type = typename traits::data_type; 45 | private: 46 | E1 const& _x; //!< First expression for addition 47 | E2 const& _y; //!< Second expression for addition 48 | public: 49 | // ------------------------------------------------------------------------------------------------------ 50 | /// @brief Sets the expressions for addition and checks that they have the same ranks and dimension 51 | /// @param[in] x The first expression for addition. 52 | /// @param[in] y The second expression for addition 53 | // ------------------------------------------------------------------------------------------------------ 54 | TensorAddition(TensorExpression const& x, TensorExpression const& y); 55 | 56 | // ------------------------------------------------------------------------------------------------------ 57 | /// @brief Gets the sizes of the all the dimensions of the expression. 58 | /// @return A constant reference to the dimension size vector of the expression 59 | // ------------------------------------------------------------------------------------------------------ 60 | inline const dim_container& dim_sizes() const { return _x.dim_sizes(); } 61 | 62 | // ------------------------------------------------------------------------------------------------------ 63 | /// @brief Returns the size of the expression. 64 | /// @return The size of the tensor_addition. 65 | // ------------------------------------------------------------------------------------------------------ 66 | inline const size_type size() const { return _x.size(); } 67 | 68 | // ------------------------------------------------------------------------------------------------------ 69 | /// @brief Returns the size of the expression. 70 | /// @return The size of the tensor_addition. 71 | // ------------------------------------------------------------------------------------------------------ 72 | inline const size_type rank() const { return _x.rank(); } 73 | 74 | // ------------------------------------------------------------------------------------------------------ 75 | /// @brief Adds two elements (one from each Tensor) from the tensor expression data. 76 | /// @param[in] i The element in the expression which must be fetched. 77 | /// @return The result of the subtraction of the Tensors. 78 | // ------------------------------------------------------------------------------------------------------ 79 | inline data_type operator[](size_type i) const { return _x[i] + _y[i]; } 80 | }; 81 | 82 | // ------------------------------------- ADDITION IMPLEMENTATIONS ------------------------------------------- 83 | 84 | template 85 | TensorAddition::TensorAddition(const TensorExpression& x, 86 | const TensorExpression& y) 87 | : _x(x), _y(y) 88 | { 89 | int i = 0; 90 | while (x.dim_sizes()[i] == y.dim_sizes()[i]) ++i; // Check equality of dimension sizes 91 | 92 | // TODO: Add error throwing 93 | // Check that the ranks are equal 94 | if (x.rank() != y.rank() || i != x.rank()) ; 95 | // Throw error here 96 | } 97 | 98 | } // End namespace ftl 99 | #endif // FTL_TENSOR_ADDITION_HPP 100 | -------------------------------------------------------------------------------- /tensor/tensor_container.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for TensorConainer class to allow both static and dynamic containers 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_CONTAINER_HPP 24 | #define FTL_TENSOR_CONTAINER_HPP 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | namespace ftl { 32 | 33 | // ---------------------------------------------------------------------------------------------------------- 34 | /// @struct TensorContainer 35 | /// @brief Container for tensor data depending on if the tensor is static (dimension sizes, and hence the 36 | /// total number of elements, are known at compile time -- uses std::array) or dynamic (dimension 37 | /// sizes are not known at compile time -- uses std::vector). 38 | /// @tparam Dtype The type of data used by the tensor 39 | /// @tparam Sizes The sizes of the dimensions (optional) 40 | // ---------------------------------------------------------------------------------------------------------- 41 | template 42 | class TensorContainer; 43 | 44 | // Specialize for static containers -- for when the sizes of the dimensions are given at compile-time 45 | template 46 | class TensorContainer { 47 | public: 48 | // ---------------------------------------- ALIAS'S ----------------------------------------------------- 49 | using data_type = Dtype; 50 | using dimension_sizes = nano::list, nano::size_t...>; 51 | using dimension_product = nano::multiplies; 52 | using data_container = std::array; 53 | using dim_container = typename nano::runtime_converter::array_type; 54 | using size_type = typename data_container::size_type; 55 | using iterator = typename data_container::iterator; 56 | // ------------------------------------------------------------------------------------------------------ 57 | 58 | // ------------------------------------------------------------------------------------------------------ 59 | /// @brief Default constructor 60 | // ------------------------------------------------------------------------------------------------------ 61 | TensorContainer() {} 62 | 63 | // ------------------------------------------------------------------------------------------------------ 64 | /// @brief Contructor when given an array with the data for the container 65 | /// @param[in] data The data to use to initalize the container data with 66 | // ------------------------------------------------------------------------------------------------------ 67 | constexpr TensorContainer(data_container& data) 68 | : _data(data) {} 69 | 70 | // ------------------------------------------------------------------------------------------------------ 71 | /// @brief Move constructor for when the data is given as a literal list 72 | /// @param[in] values The first value in the literal list 73 | /// @tparam TR The type of the rest of the parameters 74 | // ------------------------------------------------------------------------------------------------------ 75 | template 76 | constexpr TensorContainer(TR&&... values) 77 | : _data{{std::forward(values)...}} {} 78 | 79 | // ------------------------------------------------------------------------------------------------------ 80 | /// @brief Gets the size (total number of elements) in the container 81 | /// @return The size of the container 82 | // ------------------------------------------------------------------------------------------------------ 83 | constexpr size_t size() const { return dimension_product::result; } 84 | 85 | // ------------------------------------------------------------------------------------------------------ 86 | /// @brief Gets an element from the container 87 | /// @param[in] i The index of the element in the container 88 | /// @return A reference to the element at the index i in the container 89 | // ------------------------------------------------------------------------------------------------------ 90 | inline data_type& operator[](size_t i) { return _data[i]; } 91 | 92 | // ------------------------------------------------------------------------------------------------------ 93 | /// @brief Gets an element from the container 94 | /// @param[in] i The index of the element in the container 95 | /// @return A reference to the element at the index i in the container 96 | // ------------------------------------------------------------------------------------------------------ 97 | inline const data_type& operator[](size_t i) const { return _data[i]; } 98 | 99 | // ------------------------------------------------------------------------------------------------------ 100 | /// @brief Returns an iterator to the first element of the container 101 | /// @return An iterator to the first element of the container 102 | // ------------------------------------------------------------------------------------------------------ 103 | iterator begin() { return _data.begin(); } 104 | 105 | // ------------------------------------------------------------------------------------------------------ 106 | /// @brief Returns an iterator to the element following the last element 107 | /// @return An iterator to the element following the last element 108 | // ------------------------------------------------------------------------------------------------------ 109 | iterator end() { return _data.end(); } 110 | private: 111 | data_container _data; //!< Static data for a tensor 112 | }; 113 | 114 | // Specialization for dynamic container which the dimension sizes 115 | // (and hence the number of elements) are not known at compile time 116 | template 117 | class TensorContainer { 118 | public: 119 | // ----------------------------------------- ALIAS'S ---------------------------------------------------- 120 | using data_type = Dtype; 121 | using data_container = std::vector; 122 | using size_type = typename data_container::size_type; 123 | using dim_container = std::vector; 124 | using iterator = typename data_container::iterator; 125 | // ------------------------------------------------------------------------------------------------------ 126 | 127 | // ------------------------------------------------------------------------------------------------------ 128 | /// @brief Default constructor 129 | // ------------------------------------------------------------------------------------------------------ 130 | TensorContainer() : _size(0), _data(0) {} 131 | 132 | // ------------------------------------------------------------------------------------------------------ 133 | /// @brief Contructor when given an array with the data for the container 134 | /// @param[in] data The data to use to initalize the container data with 135 | // ------------------------------------------------------------------------------------------------------ 136 | TensorContainer(data_container& data) 137 | : _size(data.size()), _data(data){} 138 | 139 | // ------------------------------------------------------------------------------------------------------ 140 | /// @brief Gets the size (total number of elements) in the container 141 | /// @return The size of the container 142 | // ------------------------------------------------------------------------------------------------------ 143 | inline size_t size() const { return _size; } 144 | 145 | // ------------------------------------------------------------------------------------------------------ 146 | /// @brief Gets an element from the container 147 | /// @param[in] i The index of the element in the container 148 | /// @return A reference to the element at the index i in the container 149 | // ------------------------------------------------------------------------------------------------------ 150 | inline data_type& operator[](size_t i) { return _data[i]; } 151 | 152 | // ------------------------------------------------------------------------------------------------------ 153 | /// @brief Gets an element from the container 154 | /// @param[in] i The index of the element in the container 155 | /// @return A reference to the element at the index i in the container 156 | // ------------------------------------------------------------------------------------------------------ 157 | inline const data_type& operator[](size_t i) const { return _data[i]; } 158 | 159 | // ------------------------------------------------------------------------------------------------------ 160 | /// @brief Returns an iterator to the first element of the container 161 | /// @return An iterator to the first element of the container 162 | // ------------------------------------------------------------------------------------------------------ 163 | iterator begin() { return _data.begin(); } 164 | 165 | // ------------------------------------------------------------------------------------------------------ 166 | /// @brief Returns an iterator to the element following the last element 167 | /// @return An iterator to the element following the last element 168 | // ------------------------------------------------------------------------------------------------------ 169 | iterator end() { return _data.end(); } 170 | private: 171 | data_container _data; //!< Dynamic data container for a tensor 172 | size_t _size; //!< Number of elements in the container 173 | }; 174 | 175 | } // End namespace ftl 176 | 177 | #endif // FTL_TENSOR_CONTAINER_HPP 178 | -------------------------------------------------------------------------------- /tensor/tensor_dynamic_cpu.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor specialization with a dynamic container using the cpu. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with Tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_DYNAMIC_CPU_HPP 24 | #define FTL_TENSOR_DYNAMIC_CPU_HPP 25 | 26 | #include "mapper.hpp" 27 | #include "tensor_expression_dynamic_cpu.hpp" // NOTE: Only including expression specialization for 28 | // dynamic cpu implementation -- all specializations 29 | // are provided by tensor_expressions.hpp 30 | 31 | #include 32 | #include 33 | 34 | // NOTE : Using long template names results in extremely bulky code, so the following abbreviations are 35 | // used to reduve the bulk for template parameters: 36 | // - DT = Dtype = data type 37 | // - SF = SizeFirst = size of first dimension 38 | // - SR = SizeRest = size of other dimensions 39 | // - CPU = CPU = CPU device used for computation 40 | namespace ftl { 41 | 42 | // Forward declaration of TensorInterface so that we can provide the specialization 43 | template 44 | class TensorInterface; 45 | 46 | // Type alias for dynamic cpu tensor to make the code more readable 47 | template 48 | using DynamicTensorCpu = TensorInterface>; 49 | 50 | // Specialization for a tensor using a dynamic container and CPU devices 51 | template 52 | class TensorInterface> : public TensorExpression , 53 | TensorTraits> { 54 | public: 55 | // ---------------------------------------- ALIAS'S ----------------------------------------------------- 56 | using traits = TensorTraits; 57 | using container_type = typename traits::container_type; 58 | using data_container = typename traits::data_container; 59 | using dim_container = typename traits::dim_container; 60 | using data_type = typename traits::data_type; 61 | using size_type = typename traits::size_type; 62 | // ------------------------------------------------------------------------------------------------------ 63 | 64 | // ------------------------------------------------------------------------------------------------------ 65 | /// @brief Default constructor - sets the data to have no elements, the rank to the specified rank 66 | // ------------------------------------------------------------------------------------------------------ 67 | explicit TensorInterface(size_type rank) : _data(0), _rank(rank), _dim_sizes(rank) {} 68 | 69 | // ------------------------------------------------------------------------------------------------------ 70 | /// @brief Constructor using vectors to set the dimension sizes and the data of the tensor. Moves the 71 | /// data if the data are passed as rvalue references. 72 | /// @param dim_sizes The sizes of each of the dimensions for the tensor. 73 | /// @param data The data for the tensor. 74 | // ------------------------------------------------------------------------------------------------------ 75 | TensorInterface(dim_container& dim_sizes, data_container& data); 76 | 77 | // ------------------------------------------------------------------------------------------------------ 78 | /// @brief Constructor using vectors to set the dimension sizes and the data of the tensor. Moves the 79 | /// data if the data are passed as rvalue references. 80 | /// @param dim_sizes The sizes of each of the dimensions for the tensor. 81 | /// @param data The data for the tensor. 82 | // ------------------------------------------------------------------------------------------------------ 83 | TensorInterface(dim_container&& dim_sizes, data_container&& data); 84 | 85 | // ------------------------------------------------------------------------------------------------------ 86 | /// @brief Constructor using an initializer list - sets the size of each of the dimensions to the 87 | /// values in the intializer_list and the total number of elements equal to the product of 88 | /// the dimension sizes. 89 | /// @param[in] dim_sizes The list of dimension sizes where the nth element in the list sets the size 90 | /// of the nth dimension of the tensor. 91 | // ------------------------------------------------------------------------------------------------------ 92 | TensorInterface(std::initializer_list dim_sizes); 93 | 94 | // ------------------------------------------------------------------------------------------------------ 95 | /// @brief Constructor for creation from a tensor expression -- this is only used for simple 96 | /// expressions (which do not modify the rank and/or dimension sizes) -- such as addition 97 | /// and subtraction. Rank modifying expressions-- such as multiplication and slicing -- have 98 | /// specialized constructors (to be implemented). 99 | /// @param[in] expression The expression instance to create the static tensor from 100 | /// @tparam Expression The type of the expressionA 101 | /// @tparam Traits The tensor traits of the expression 102 | // ------------------------------------------------------------------------------------------------------ 103 | template 104 | TensorInterface(const TensorExpression& expression); 105 | 106 | // ------------------------------------------------------------------------------------------------------ 107 | /// @brief Gets the rank (number of dimensions) of the tensor. 108 | /// @return The rank (number of dimensions) of the tensor. 109 | // ------------------------------------------------------------------------------------------------------ 110 | inline size_type rank() const { return _rank; } 111 | 112 | // ------------------------------------------------------------------------------------------------------ 113 | /// @brief Gets the size (total number of elements) of the tensor 114 | /// @return The total number of elements in the tensor. 115 | // ------------------------------------------------------------------------------------------------------ 116 | inline size_type size() const { return _data.size(); } 117 | 118 | // NOTE: need to add out of range exception here too 119 | // ------------------------------------------------------------------------------------------------------ 120 | /// @brief Gets the size of a specific dimension of the tensor, if the requested dimension is 121 | /// invalid then 0 is returned. 122 | /// @param[in] dim The dimension for which the size must be returned. 123 | /// @return The number of elements in the requested dimension, if the dimension is a valid dimension 124 | /// for the tensor, otherwise 0 is returned. 125 | // ------------------------------------------------------------------------------------------------------ 126 | inline size_t size(const int dim) const { return dim < _rank ? _dim_sizes[dim] : 0; } 127 | 128 | // ------------------------------------------------------------------------------------------------------ 129 | /// @brief Gets a vector holding the size of each dimension of the tensor. 130 | /// @return A vector holding the size of each dimension of the tensor. 131 | // ------------------------------------------------------------------------------------------------------ 132 | const dim_container& dim_sizes() const { return _dim_sizes; } 133 | 134 | // ------------------------------------------------------------------------------------------------------ 135 | /// @brief Gets the tensor data. 136 | /// @return The data for the tensor. 137 | // ------------------------------------------------------------------------------------------------------ 138 | const data_container& data() const { return _data; } 139 | 140 | // ------------------------------------------------------------------------------------------------------ 141 | /// @brief Initializes each element of the tensor between a range using a uniform ditribution 142 | /// @param[in] min The minimum value of an element after the initialization 143 | /// @param[in] max The max value of an element after the initialization 144 | // ------------------------------------------------------------------------------------------------------ 145 | void initialize(const data_type min, const data_type max); 146 | 147 | // ------------------------------------------------------------------------------------------------------ 148 | /// @brief Gets the element at position i in the tensor's data vector, by refernce 149 | /// @param[in] i The index of the element to access. 150 | /// @return The element at position i in the tensor's data vecor. 151 | // ------------------------------------------------------------------------------------------------------ 152 | inline data_type& operator[](size_type i) { return _data[i]; } 153 | 154 | // ------------------------------------------------------------------------------------------------------ 155 | /// @brief Gets the element at position i in the tensor's data vector, by value. 156 | /// @param[in] i The index of the element to access. 157 | /// @return The element at position i in the tensor's data vector. 158 | // ------------------------------------------------------------------------------------------------------ 159 | inline const data_type& operator[](size_type i) const { return _data[i]; } 160 | 161 | // ------------------------------------------------------------------------------------------------------ 162 | /// @brief Gets the element at a given index for each dimension of a tensor -- there is no bound 163 | /// checking as bound checking implementations will be provided through .at() 164 | /// @param[in] index_dim_one The index of the element in dimension 1 165 | /// @param[in] index_dim_other The index of the element in the other dimensions 166 | /// @tparam IF The type of the first index parameter 167 | /// @tparam IR The types of the rest of the index parameters 168 | /// @return A reference to the element at the position given by the indices 169 | // ------------------------------------------------------------------------------------------------------ 170 | template 171 | DT& operator()(IF index_dim_one, IR... index_dim_other); 172 | 173 | // ------------------------------------------------------------------------------------------------------ 174 | /// @brief Gets the element at a given index for each dimension of a tensor -- there is no bound 175 | /// checking as bound checking implementations will be provided through .at() 176 | /// @param[in] index_dim_one The index of the element in dimension 1 177 | /// @param[in] index_dim_other The index of the element in the other dimensions 178 | /// @tparam IF The type of the first index parameter 179 | /// @tparam IR The types of the rest of the index parameters 180 | /// @return The value of the element at the position given by the indices 181 | // ------------------------------------------------------------------------------------------------------ 182 | template 183 | DT operator()(IF index_dim_one, IR... index_dim_other) const; 184 | private: 185 | data_container _data; //!< Data for the tensor 186 | dim_container _dim_sizes; //!< Sizes of the dimensions for the tensor 187 | size_type _rank; //!< The rank (number of dimensions) in the tensor 188 | }; 189 | 190 | // ------------------------------------------- IMPLEMENTATIONS ---------------------------------------------- 191 | 192 | // ----------------------------------------------- PUBLIC --------------------------------------------------- 193 | 194 | template 195 | TensorInterface>::TensorInterface(std::initializer_list dim_sizes) 196 | : _data(std::accumulate(dim_sizes.begin(), dim_sizes.end(), 1, std::multiplies())), 197 | _rank(dim_sizes.size()) 198 | { 199 | for (auto& element : dim_sizes) _dim_sizes.push_back(element); 200 | } 201 | 202 | template 203 | TensorInterface>::TensorInterface(dim_container& dim_sizes, data_container& data) 204 | : _data(data), _rank(dim_sizes.size()), _dim_sizes(dim_sizes) 205 | { 206 | // TODO: Add exception checking that the number of elements in the data container is the same as the 207 | // product of the sizes of the dimensions that were given 208 | 209 | } 210 | 211 | template 212 | TensorInterface>::TensorInterface(dim_container&& dim_sizes, data_container&& data) 213 | : _data(data), _rank(dim_sizes.size()), _dim_sizes(dim_sizes) 214 | { 215 | // TODO: Add exception checking that the number of elements in the data container is the same as the 216 | // product of the sizes of the dimensions that were given 217 | 218 | } 219 | 220 | template template 221 | TensorInterface>::TensorInterface(const TensorExpression& expression) 222 | : _data(expression.size()), _dim_sizes(expression.dim_sizes()), _rank(expression.rank()) 223 | { 224 | for (size_type i = 0; i != size(); ++i) _data[i] = expression[i]; 225 | } 226 | 227 | template 228 | void TensorInterface>::initialize(const data_type min, const data_type max) 229 | { 230 | std::random_device rand_device; 231 | std::mt19937 gen(rand_device()); 232 | std::uniform_real_distribution<> dist(min, max); 233 | for (auto& element : _data) element = static_cast(dist(gen)); 234 | } 235 | 236 | template template 237 | DT& TensorInterface>::operator()(IF dim_one_index, IR... other_dim_indices) 238 | { 239 | return _data[DynamicMapper::indices_to_index(_dim_sizes, dim_one_index, other_dim_indices...)]; 240 | } 241 | 242 | template template 243 | DT TensorInterface>::operator()(IF dim_one_index, IR... other_dim_indices) const 244 | { 245 | return _data[DynamicMapper::indices_to_index(_dim_sizes, dim_one_index, other_dim_indices...)]; 246 | } 247 | 248 | } // End namespace ftl 249 | #endif // FTL_TENSOR_DYNAMIC_CPU_HPP 250 | -------------------------------------------------------------------------------- /tensor/tensor_expression_dynamic_cpu.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor expressions dynamic container and cpu specialization for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_EXPRESSIONS_DYNAMIC_CPU_HPP 24 | #define FTL_TENSOR_EXPRESSIONS_DYNAMIC_CPU_HPP 25 | 26 | #include "tensor_expression_interface.hpp" 27 | 28 | namespace ftl { 29 | 30 | // Specialization for tensor expression with dynamic container and cpu implemenation traits 31 | template 32 | class TensorExpression> { 33 | public: 34 | // ---------------------------------------- ALIAS'S ----------------------------------------------------- 35 | using traits = TensorTraits; 36 | using size_type = typename traits::size_type; 37 | using data_type = typename traits::data_type; 38 | using container_type = typename traits::container_type; 39 | using data_container = typename traits::data_container; 40 | using dim_container = typename traits::dim_container; 41 | // ------------------------------------------------------------------------------------------------------ 42 | 43 | // ------------------------------------------------------------------------------------------------------ 44 | /// @brief Gets a pointer to the expression. 45 | /// @return A non-const pointer to the expression. 46 | // ------------------------------------------------------------------------------------------------------ 47 | Expression* expression() { return static_cast(this); } 48 | 49 | // ------------------------------------------------------------------------------------------------------ 50 | /// @brief Gets a const pointer to the expression. 51 | /// @return A const pointer to the expression. 52 | // ------------------------------------------------------------------------------------------------------ 53 | const Expression* expression() const { return static_cast(this); } 54 | 55 | // ------------------------------------------------------------------------------------------------------ 56 | //! @brief Gets a reference to the Tensor expression. 57 | //! @return A reference to the Tensor expression E. 58 | // ------------------------------------------------------------------------------------------------------ 59 | operator Expression&() { return static_cast(*this); } 60 | 61 | // ------------------------------------------------------------------------------------------------------ 62 | //! @brief Gets a constant reference to the Tensor expression. 63 | //! @return A constant reference to the Tensror expression E. 64 | // ------------------------------------------------------------------------------------------------------ 65 | operator Expression const&() const { return static_cast(*this); } 66 | 67 | // ------------------------------------------------------------------------------------------------------ 68 | //! @brief Returns the size of the expression 69 | //! @return The size of the tensor_expression 70 | // ------------------------------------------------------------------------------------------------------ 71 | size_type size() const { return expression()->size(); } 72 | 73 | // ------------------------------------------------------------------------------------------------------ 74 | /// @brief Returns the rank of the expression 75 | /// @return The rank of the expression 76 | // ------------------------------------------------------------------------------------------------------ 77 | size_type rank() const { return expression()->rank(); } 78 | 79 | // ------------------------------------------------------------------------------------------------------ 80 | //! @brief Gets the sizes of the all the dimensions of the expression. 81 | //! @return A constant reference to the dimension size vector of the expression 82 | // ------------------------------------------------------------------------------------------------------ 83 | const dim_container& dim_sizes() const { return expression()->dim_sizes(); } 84 | 85 | // ------------------------------------------------------------------------------------------------------ 86 | //! @brief Gets and element from the Tensor expression data. 87 | //! @param[in] i The element in the expression which must be fetched. 88 | //! @return The value of the element at position i of the expression data. 89 | // ------------------------------------------------------------------------------------------------------ 90 | inline data_type& operator[](size_type i) { return expression()->operator[](i); } 91 | 92 | // ------------------------------------------------------------------------------------------------------ 93 | //! @brief Gets and element from the Tensor expression data. 94 | //! @param[in] i The element in the expression which must be fetched. 95 | //! @return The value of the element at position i of the expression data. 96 | // ------------------------------------------------------------------------------------------------------ 97 | inline const data_type& operator[](size_type i) const { return expression()->operator[](i); } 98 | }; 99 | 100 | } // End namespace ftl 101 | #endif // FTL_TENSOR_EXPRESSIONS_DYNAMIC_CPU_HPP 102 | -------------------------------------------------------------------------------- /tensor/tensor_expression_interface.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor expression interface for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_EXPRESSION_INTERFACE_HPP 24 | #define FTL_TENSOR_EXPRESSION_INTERFACE_HPP 25 | 26 | #include "tensor_traits.hpp" 27 | 28 | namespace ftl { 29 | 30 | // NOTE : All specializations are defined in their own files as: 31 | // - tensor_expressions__,hpp 32 | // 33 | // : where 34 | // - container_type = type of container (static_or dynamic) 35 | // - device_type = type of device (cpu gpu, any) 36 | // 37 | // any = not yet implemented for a specific device, or can operate on both 38 | 39 | 40 | // ---------------------------------------------------------------------------------------------------------- 41 | /// @class TensorExpression 42 | /// @brief Defines a general tensor expression so that opertions on tensor expressions can be defined 43 | /// the syntax of the operations to look as they would mathematically. 44 | /// @tparam Expression The expression 45 | /// @tparam Traits The traits which define the expression, for example specifying that the 46 | /// expression uses static containers and GPU implemenations 47 | // ---------------------------------------------------------------------------------------------------------- 48 | template 49 | class TensorExpression; 50 | 51 | } // End namespace ftl 52 | #endif // FTL_TENSOR_EXPRESSION_INTERFACE_HPP 53 | -------------------------------------------------------------------------------- /tensor/tensor_expression_static_cpu.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor expressions static container and cpu specialization for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_EXPRESSIONS_STATIC_CPU_HPP 24 | #define FTL_TENSOR_EXPRESSIONS_STATIC_CPU_HPP 25 | 26 | #include "tensor_expression_interface.hpp" 27 | 28 | // NOTE: Some of the template parameters are abbreviated as (IMHO) it looks cleaner, so: 29 | // - DT = Dtype = type of data used 30 | // - SF = SizeFirst = size of the first dimension 31 | // - SR = SizeRest = sizes of the rest of the dimensions 32 | 33 | namespace ftl { 34 | 35 | // Specialization for tensor expression with static container and cpu implementation traits 36 | template 37 | class TensorExpression> { 38 | public: 39 | // ---------------------------------------- ALIAS'S ----------------------------------------------------- 40 | using traits = TensorTraits; 41 | using size_type = typename traits::size_type; 42 | using data_type = typename traits::data_type; 43 | using container_type = typename traits::container_type; 44 | using data_container = typename traits::data_container; 45 | using dim_container = typename traits::dim_container; 46 | // ------------------------------------------------------------------------------------------------------ 47 | 48 | // ------------------------------------------------------------------------------------------------------ 49 | /// @brief Gets a pointer to the expression. 50 | /// @return A non-const pointer to the expression. 51 | // ------------------------------------------------------------------------------------------------------ 52 | Expression* expression() { return static_cast(this); } 53 | 54 | // ------------------------------------------------------------------------------------------------------ 55 | /// @brief Gets a const pointer to the expression. 56 | /// @return A const pointer to the expression. 57 | // ------------------------------------------------------------------------------------------------------ 58 | const Expression* expression() const { return static_cast(this); } 59 | 60 | // ------------------------------------------------------------------------------------------------------ 61 | //! @brief Gets a reference to the Tensor expression. 62 | //! @return A reference to the Tensor expression E. 63 | // ------------------------------------------------------------------------------------------------------ 64 | operator Expression&() { return static_cast(*this); } 65 | 66 | // ------------------------------------------------------------------------------------------------------ 67 | //! @brief Gets a constant reference to the Tensor expression. 68 | //! @return A constant reference to the Tensror expression E. 69 | // ------------------------------------------------------------------------------------------------------ 70 | operator Expression const&() const { return static_cast(*this); } 71 | 72 | // ------------------------------------------------------------------------------------------------------ 73 | /// @brief Returns the size of the expression 74 | /// @return The size of the expression 75 | // ------------------------------------------------------------------------------------------------------ 76 | constexpr size_type size() const { return expression()->size(); } 77 | 78 | // ------------------------------------------------------------------------------------------------------ 79 | /// @brief Returns the rank of the expression 80 | /// @return The rank of the expression 81 | // ------------------------------------------------------------------------------------------------------ 82 | constexpr size_type rank() const { return expression()->rank(); } 83 | 84 | // ------------------------------------------------------------------------------------------------------ 85 | //! @brief Gets the sizes of the all the dimensions of the expression. 86 | //! @return A constant reference to the dimension size vector of the expression 87 | // ------------------------------------------------------------------------------------------------------ 88 | constexpr const dim_container& dim_sizes() const { return expression()->dim_sizes(); } 89 | 90 | // ------------------------------------------------------------------------------------------------------ 91 | //! @brief Gets and element from the Tensor expression data. 92 | //! @param[in] i The element in the expression which must be fetched. 93 | //! @return The value of the element at position i of the expression data. 94 | // ------------------------------------------------------------------------------------------------------ 95 | inline data_type& operator[](size_type i) { return expression()->operator[](i); } 96 | 97 | // ------------------------------------------------------------------------------------------------------ 98 | //! @brief Gets and element from the Tensor expression data. 99 | //! @param[in] i The element in the expression which must be fetched. 100 | //! @return The value of the element at position i of the expression data. 101 | // ------------------------------------------------------------------------------------------------------ 102 | inline const data_type& operator[](size_type i) const { return expression()->operator[](i); } 103 | }; 104 | 105 | } // End namespace ftl 106 | #endif // FTL_TENSOR_EXPRESSIONS_STATIC_CPU_HPP 107 | -------------------------------------------------------------------------------- /tensor/tensor_expressions.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor expressions for the tensor library -- includes all partial specializations 3 | /// for the tensor expressions. The file is intended to be included in an aplication where all tensor 4 | /// expression functionality is required. It will reduce compilation time, so when using a specific 5 | /// expression implementation -- say static contatiers with a GPU -- include only that file. 6 | // ---------------------------------------------------------------------------------------------------------- 7 | 8 | /* 9 | * ---------------------------------------------------------------------------------------------------------- 10 | * Tensor is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published 12 | * by the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * Tensor is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with tensor; if not, write to the Free Software Foundation, 22 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | * ---------------------------------------------------------------------------------------------------------- 24 | */ 25 | 26 | #ifndef FTL_TENSOR_EXPRESSIONS_HPP 27 | #define FTL_TENSOR_EXPRESSIONS_HPP 28 | 29 | #include "tensor_expression_dynamic_cpu.hpp" 30 | #include "tensor_expression_static_cpu.hpp" 31 | 32 | #endif // FTL_TENSOR_EXPRESSIONS_HPP 33 | 34 | -------------------------------------------------------------------------------- /tensor/tensor_operations.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor operations for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_OPERATIONS_HPP 24 | #define FTL_TENSOR_OPERATIONS_HPP 25 | 26 | #include "tensor_addition.hpp" 27 | #include "tensor_subtraction.hpp" 28 | 29 | // Unnamed namespace so that operations are available everywhere 30 | namespace { 31 | 32 | // ---------------------------------------------------------------------------------------------------------- 33 | /// @brief Adds two tensor expressions 34 | /// @param[in] x The first expression to add 35 | /// @param[in] y The second expression to add 36 | /// @return The result of the addition of the two tensor_expressions. 37 | /// @tparam E1 The type of the first expression for the addition 38 | /// @tparam E2 The type of the second expression for the addition 39 | /// @tparam T1 The traits of the first tensors -- for addition the traits for the returned tensor are 40 | /// the same as the first tensor for additio 41 | /// @tparam T2 The traits of the second expression 42 | // ---------------------------------------------------------------------------------------------------------- 43 | template 44 | const ftl::TensorAddition operator+(ftl::TensorExpression const& x, 45 | ftl::TensorExpression const& y) 46 | { 47 | return ftl::TensorAddition(x, y); 48 | } 49 | 50 | // ---------------------------------------------------------------------------------------------------------- 51 | /// @brief Subtracts two tensor expressions 52 | /// @param[in] x The first expression to subtract from 53 | /// @param[in] y The second expression to subtract with 54 | /// @return The result of the subtraction of the two tensor_expressions. 55 | /// @tparam E1 The type of the first expression for the subtraction 56 | /// @tparam E2 The type of the second expression for the subtraction 57 | /// @tparam T1 The traits of the first tensors -- for subtraction the traits for the returned tensor are 58 | /// the same as the first tensor for additio 59 | /// @tparam T2 The traits of the second expression 60 | // ---------------------------------------------------------------------------------------------------------- 61 | template 62 | const ftl::TensorSubtraction operator-(ftl::TensorExpression const& x, 63 | ftl::TensorExpression const& y) 64 | { 65 | return ftl::TensorSubtraction(x, y); 66 | } 67 | 68 | } // End unnamed namespace 69 | #endif // FTL_TENSOR_OPERATIONS_HPP 70 | -------------------------------------------------------------------------------- /tensor/tensor_static_cpu.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor specialization with a static container using the cpu. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_STATIC_CPU_HPP 24 | #define FTL_TENSOR_STATIC_CPU_HPP 25 | 26 | #include 27 | #include "mapper.hpp" 28 | #include "tensor_expression_static_cpu.hpp" // NOTE: Only including expression specialization for 29 | // static cpu implementation -- all specializations 30 | // are provided by tensor_expressions.hpp 31 | 32 | #include 33 | 34 | // NOTE : Using long template names results in extremely bulky code, so the following abbreviations are 35 | // used to reduve the bulk for template parameters: 36 | // - DT = Dtype = data type 37 | // - SF = SizeFirst = size of first dimension 38 | // - SR = SizeRest = size of other dimensions 39 | namespace ftl { 40 | 41 | // Forward declaration of TensorInterface so that we can provide the specialization 42 | template 43 | class TensorInterface; 44 | 45 | // Type alias for static cpu tensor to make the code more readable 46 | template 47 | using StaticTensorCpu = TensorInterface>; 48 | 49 | // Specialization for a tensor using a static container and a CPU device 50 | template 51 | class TensorInterface> : public TensorExpression< 52 | StaticTensorCpu , 53 | TensorTraits> { 54 | public: 55 | // ---------------------------------------- ALIAS'S ----------------------------------------------------- 56 | using traits = TensorTraits; 57 | using size_type = typename traits::size_type; 58 | using data_type = typename traits::data_type; 59 | using container_type = typename traits::container_type; 60 | using data_container = typename container_type::data_container; 61 | using dim_container = typename container_type::dim_container; 62 | // ------------------------------------------------------------------------------------------------------ 63 | 64 | // ------------------------------------------------------------------------------------------------------ 65 | /// @brief Default constructor, converts the compile time list of dimension sizes to an array 66 | // ------------------------------------------------------------------------------------------------------ 67 | TensorInterface(); 68 | 69 | // ------------------------------------------------------------------------------------------------------ 70 | /// @brief Constructor for when the data is given as an lvalue 71 | /// @param[in] data The data to use for the tensor 72 | // ------------------------------------------------------------------------------------------------------ 73 | TensorInterface(data_container& data); 74 | 75 | // ------------------------------------------------------------------------------------------------------ 76 | /// @brief Constructor for when the data is specified as a literal list 77 | /// @param[in] first_value The first value in the literal list -- must be data_type 78 | /// @param[in] other_values The other values which make up the data 79 | /// @tparam TR The type of the rest of the values 80 | // ------------------------------------------------------------------------------------------------------ 81 | template 82 | TensorInterface(DT&& first_value, TR&&... other_values); 83 | 84 | // ------------------------------------------------------------------------------------------------------ 85 | /// @brief Constructor for creation from a tensor expression -- this is only used for simple 86 | /// expressions (which do not modify the rank and/or dimension sizes) -- such as addition 87 | /// and subtraction. Rank modifying expressions-- such as multiplication and slicing -- have 88 | /// specialized constructors (to be implemented). 89 | /// @param[in] expression The expression instance to create the static tensor from 90 | /// @tparam Expression The type of the expression 91 | // ------------------------------------------------------------------------------------------------------ 92 | template 93 | TensorInterface(const TensorExpression& expression); 94 | 95 | // ------------------------------------------------------------------------------------------------------ 96 | /// @brief Gets the rank (number of dimensions) of the tensor 97 | /// @return The rank (number of dimensions) of the tensor 98 | // ------------------------------------------------------------------------------------------------------ 99 | constexpr size_type rank() const { return sizeof...(SR) + 1; } 100 | 101 | // ------------------------------------------------------------------------------------------------------ 102 | /// @brief Gets the size (total number of elements) in the tensor 103 | /// @return The size of the tensor 104 | // ------------------------------------------------------------------------------------------------------ 105 | constexpr size_type size() const { return _data.size(); } 106 | 107 | // TODO: Add out of range exception 108 | // ------------------------------------------------------------------------------------------------------ 109 | /// @brief Gets the size (total number of elements) in a specific dimension of the tensor, if the 110 | /// dimension is valid 111 | /// @param[in] dim The dimension to get the size of 112 | /// @return The size of the requested dimension of the tensor if valid, otherwise 0 113 | // ------------------------------------------------------------------------------------------------------ 114 | inline size_type size(const size_type dim) const { return dim < rank() ? _dim_sizes[dim] : 0; } 115 | 116 | // ------------------------------------------------------------------------------------------------------ 117 | /// @brief Gets a reference to the container holding the sizes of the dimensions for the tensor 118 | /// @return A constant reference to the dimension sizes of the tensor 119 | // ------------------------------------------------------------------------------------------------------ 120 | constexpr const dim_container& dim_sizes() const { return _dim_sizes; } 121 | 122 | // ------------------------------------------------------------------------------------------------------ 123 | /// @brief Initializes each element of the tensor between a range using a uniform ditribution 124 | /// @param[in] min The minimum value of an element after the initialization 125 | /// @param[in] max The max value of an element after the initialization 126 | // ------------------------------------------------------------------------------------------------------ 127 | void initialize(const data_type min, const data_type max); 128 | 129 | // ------------------------------------------------------------------------------------------------------ 130 | /// @brief Gets an element from the tensor 131 | /// @param[in] i The index of the element in the tensor 132 | /// @return A reference to the element at the index i in the tensor 133 | // ------------------------------------------------------------------------------------------------------ 134 | inline data_type& operator[](size_type i) { return _data[i]; } 135 | 136 | // ------------------------------------------------------------------------------------------------------ 137 | /// @brief Gets an element from the tensor 138 | /// @param[in] i The index of the element in the tensor 139 | /// @return The value of the element at the index i in the tensor 140 | // ------------------------------------------------------------------------------------------------------ 141 | inline const data_type& operator[](size_type i) const { return _data[i]; } 142 | 143 | // ------------------------------------------------------------------------------------------------------ 144 | /// @brief Gets the element at a given index for each dimension of a tensor -- there is no bound 145 | /// checking as bound checking implementations will be provided through .at() 146 | /// @param[in] index_dim_one The index of the element in dimension 1 147 | /// @param[in] index_dim_other The index of the element in the other dimensions 148 | /// @tparam IF The type of the first index parameter 149 | /// @tparam IR The types of the rest of the index parameters 150 | /// @return A reference to the element at the position given by the indices 151 | // ------------------------------------------------------------------------------------------------------ 152 | template 153 | DT& operator()(IF index_dim_one, IR... index_dim_other); 154 | 155 | // ------------------------------------------------------------------------------------------------------ 156 | /// @brief Gets the element at a given index for each dimension of a tensor -- there is no bound 157 | /// checking as bound checking implementations will be provided through .at() 158 | /// @param[in] index_dim_one The index of the element in dimension 1 159 | /// @param[in] index_dim_other The index of the element in the other dimensions 160 | /// @tparam IF The type of the first index parameter 161 | /// @tparam IR The types of the rest of the index parameters 162 | /// @return The value of the element at the position given by the indices 163 | // ------------------------------------------------------------------------------------------------------ 164 | template 165 | DT operator()(IF index_dim_one, IR... index_dim_other) const; 166 | private: 167 | data_container _data; //!< The data container which holds all the data 168 | dim_container _dim_sizes; //!< The sizes of the dimensions for the tensor 169 | }; 170 | 171 | // ----------------------------------------------- IMPLEMENTATIONS ------------------------------------------ 172 | 173 | // ------------------------------------------------- PUBLIC ------------------------------------------------- 174 | 175 | template 176 | TensorInterface>::TensorInterface() 177 | { 178 | // Convert the nano::list of dimension sizes to a constant array 179 | _dim_sizes = nano::runtime_converter::to_array(); 180 | }; 181 | 182 | template 183 | TensorInterface>::TensorInterface(data_container& data) 184 | : _data(data) 185 | { 186 | // Convert the nano::list of dimension sizes to a constant array 187 | _dim_sizes = nano::runtime_converter::to_array(); 188 | } 189 | 190 | template template 191 | TensorInterface>::TensorInterface(DT&& first_value, TR&&... other_values) 192 | : _data{{std::forward
(first_value), std::forward(other_values)...}} 193 | { 194 | // Convert the nano::list of dimension sizes to a constant array 195 | _dim_sizes = nano::runtime_converter::to_array(); 196 | } 197 | 198 | template template 199 | TensorInterface>::TensorInterface(const TensorExpression& expression) 200 | { 201 | // Convert the nano::list of dimension sizes to a constant array 202 | _dim_sizes = nano::runtime_converter::to_array(); 203 | for (size_type i = 0; i != size(); ++i) _data[i] = expression[i]; 204 | } 205 | 206 | template 207 | void TensorInterface>::initialize(const data_type min, const data_type max) 208 | { 209 | std::random_device rand_device; 210 | std::mt19937 gen(rand_device()); 211 | std::uniform_real_distribution<> dist(min, max); 212 | for (auto& element : _data) element = static_cast(dist(gen)); 213 | } 214 | 215 | template template 216 | DT& TensorInterface>::operator()(IF dim_one_index, IR... other_dim_indices) 217 | { 218 | using dimension_sizes = typename container_type::dimension_sizes; 219 | return _data[StaticMapper::indices_to_index(dim_one_index, other_dim_indices...)]; 220 | } 221 | 222 | template template 223 | DT TensorInterface>::operator()(IF dim_one_index, IR... other_dim_indices) const 224 | { 225 | using dimension_sizes = typename container_type::dimension_sizes; 226 | return _data[StaticMapper::indices_to_index(dim_one_index, other_dim_indices...)]; 227 | } 228 | 229 | } // End namespace ftl 230 | #endif // FTL_TENSOR_STATIC_CPU_HPP 231 | -------------------------------------------------------------------------------- /tensor/tensor_subtraction.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor sybtraction for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_SUBTRACTION_HPP 24 | #define FTL_TENSOR_SUBTRACTION_HPP 25 | 26 | #include "tensor_expressions.hpp" 27 | 28 | namespace ftl { 29 | 30 | // ---------------------------------------------------------------------------------------------------------- 31 | /// @class TensorSubtraction 32 | /// @brief Expression class for calculating the subtraction of two tensors. 33 | /// @tparam E1 The first expression for subtraction 34 | /// @tparam E2 The second expression for subtraction 35 | /// @tparam T1 The traits of the first expression 36 | /// @tparam T2 The traits if the second expression 37 | // ---------------------------------------------------------------------------------------------------------- 38 | template 39 | class TensorSubtraction : public TensorExpression, T1> { 40 | public: 41 | using traits = T1; 42 | using dim_container = typename traits::dim_container; 43 | using size_type = typename traits::size_type; 44 | using data_type = typename traits::data_type; 45 | private: 46 | E1 const& _x; //!< First expression for subtraction 47 | E2 const& _y; //!< Second expression for subtraction 48 | public: 49 | // ------------------------------------------------------------------------------------------------------ 50 | /// @brief Sets the expressions for subtraction and checks that they have the same ranks and dimension 51 | /// @param[in] x The first expression for subtraction. 52 | /// @param[in] y The second expression for subtraction 53 | // ------------------------------------------------------------------------------------------------------ 54 | TensorSubtraction(TensorExpression const& x, TensorExpression const& y); 55 | 56 | // ------------------------------------------------------------------------------------------------------ 57 | /// @brief Gets the sizes of the all the dimensions of the expression. 58 | /// @return A constant reference to the dimension size vector of the expression 59 | // ------------------------------------------------------------------------------------------------------ 60 | inline const dim_container& dim_sizes() const { return _x.dim_sizes(); } 61 | 62 | // ------------------------------------------------------------------------------------------------------ 63 | /// @brief Returns the size of the expression. 64 | /// @return The size of the tensor_subtraction. 65 | // ------------------------------------------------------------------------------------------------------ 66 | inline const size_type size() const { return _x.size(); } 67 | 68 | // ------------------------------------------------------------------------------------------------------ 69 | /// @brief Returns the size of the expression. 70 | /// @return The size of the tensor_subtraction. 71 | // ------------------------------------------------------------------------------------------------------ 72 | inline const size_type rank() const { return _x.rank(); } 73 | 74 | // ------------------------------------------------------------------------------------------------------ 75 | /// @brief Adds two elements (one from each Tensor) from the tensor expression data. 76 | /// @param[in] i The element in the expression which must be fetched. 77 | /// @return The result of the subtraction of the Tensors. 78 | // ------------------------------------------------------------------------------------------------------ 79 | inline data_type operator[](size_type i) const { return _x[i] - _y[i]; } 80 | }; 81 | 82 | // ------------------------------------- SUBTRACTION IMPLEMENTATIONS ------------------------------------------- 83 | 84 | template 85 | TensorSubtraction::TensorSubtraction(const TensorExpression& x, 86 | const TensorExpression& y) 87 | : _x(x), _y(y) 88 | { 89 | // TODO: Add error throwing 90 | // Check that the ranks are equal 91 | if (x.rank() != y.rank() && x.dim_sizes() != y.dim_sizes()) ; 92 | // Throw error here 93 | } 94 | 95 | } // End namespace ftl 96 | #endif // FTL_TENSOR_SUBTRACTION_HPP 97 | -------------------------------------------------------------------------------- /tensor/tensor_traits.hpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file Header file for tensor traits for tensor library. 3 | // ---------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | * ---------------------------------------------------------------------------------------------------------- 7 | * Tensor is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Tensor is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with tensor; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * ---------------------------------------------------------------------------------------------------------- 21 | */ 22 | 23 | #ifndef FTL_TENSOR_TRAITS_HPP 24 | #define FTL_TENSOR_TRAITS_HPP 25 | 26 | #include "tensor_container.hpp" 27 | 28 | namespace ftl { 29 | 30 | // So that the code is more readable -- using an int rather than an enum since it will make 31 | // for easy integration with other libraries that want to enable compile time device selection 32 | using device = short; 33 | 34 | static constexpr device CPU = 0; 35 | static constexpr device GPU = 1; 36 | 37 | // ---------------------------------------------------------------------------------------------------------- 38 | /// @struct TensorTraits 39 | /// @brief Traits class which specifies parameters for a tensor, such as what type of container it uses 40 | /// and what type of device the computations should be performed on 41 | /// @tparam Dtype The type of data used by the container 42 | /// @tparam DeviceType The type of device used for computation -- CPU or GPU 43 | /// @tparam DimSizes The sizes of each of the dimensions of the tensor -- an optional parameters. 44 | /// This parameter is used to determine the container type -- static if the dimension sizes are 45 | /// specified or dynamic if they are not. 46 | // ---------------------------------------------------------------------------------------------------------- 47 | template 48 | struct TensorTraits; 49 | 50 | // Specialize for static container 51 | template 52 | struct TensorTraits { 53 | // ---------------------------------------- ALIAS'S ----------------------------------------------------- 54 | using data_type = Dtype; 55 | using container_type = TensorContainer; 56 | using data_container = typename container_type::data_container; 57 | using dim_container = typename container_type::dim_container; 58 | using size_type = typename container_type::size_type; 59 | // ------------------------------------------------------------------------------------------------------ 60 | static constexpr device device_type = DeviceType; 61 | }; 62 | 63 | // Specialize for dynamic container 64 | template 65 | struct TensorTraits { 66 | // ---------------------------------------- ALIAS'S ----------------------------------------------------- 67 | using data_type = Dtype; 68 | using container_type = TensorContainer; 69 | using data_container = typename container_type::data_container; 70 | using dim_container = typename container_type::dim_container; 71 | using size_type = typename container_type::size_type; 72 | // ------------------------------------------------------------------------------------------------------}; 73 | static constexpr device device_type = DeviceType; 74 | }; 75 | 76 | } // End namespace ftl 77 | #endif // FTL_TENSOR_TRAITS_HPP 78 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # EXECUTABLE NAME # 3 | # # 4 | # NOTE: The following conventions are used: # 5 | # # 6 | # - CU = CUDA related variables # 7 | # - CX = C++ related variables # 8 | ######################################################################################## 9 | 10 | EXE := test_suite 11 | CONTAINER_EXE := container_suite 12 | OPERATIONS_EXE := operations_suite 13 | TENSOR_EXE := tensor_suite 14 | TRAITS_EXE := traits_suite 15 | 16 | 17 | ######################################################################################## 18 | # COMPILERS # 19 | # # 20 | # NOTE: Compiling with cuda because GPU support will be added # 21 | ######################################################################################## 22 | 23 | HOST_COMPILER := clang++ 24 | NVCC := nvcc -ccbin $(HOST_COMPILER) 25 | CXX := clang++ 26 | 27 | ######################################################################################## 28 | # INCLUDE DIRECTORIES # 29 | ######################################################################################## 30 | 31 | CU_INC := 32 | CX_INC := 33 | 34 | ######################################################################################## 35 | # LIBRARIES # 36 | ######################################################################################## 37 | 38 | CU_LIBS := 39 | CX_LIBS := -lboost_unit_test_framework 40 | 41 | CU_LDIR := 42 | CX_LDIR := 43 | 44 | ######################################################################################## 45 | # COMPILER FLAGS # 46 | # # 47 | # NOTE: To enable compiler warnings, remove -w and replace with : # 48 | # --compiler-options -Wall # 49 | ######################################################################################## 50 | 51 | CU_FLAGS := 52 | CX_FLAGS := -std=c++11 -w 53 | 54 | DG_FLAGS := -g 55 | RE_FLAGS := -O3 56 | 57 | TP_FLAGS := $(CX_FLAGS) 58 | 59 | ######################################################################################## 60 | # TARGET RULES # 61 | ####################################################################################### 62 | 63 | .PHONY: all container operations tensor traits 64 | 65 | all: debug 66 | 67 | debug: CX_FLAGS += $(DG_FLAGS) 68 | debug: build_tests 69 | 70 | operations_tests.o: operations_tests.cpp 71 | $(CXX) $(CU_INC) $(CU_FLAGS) $(CX_INC) $(CX_FLAGS) -o $@ -c $< 72 | 73 | container_tests.o: container_tests.cpp 74 | $(CXX) $(CU_INC) $(CU_FLAGS) $(CX_INC) $(CX_FLAGS) -o $@ -c $< 75 | 76 | tensor_tests.o: tensor_tests.cpp 77 | $(CXX) $(CU_INC) $(CU_FLAGS) $(CX_INC) $(CX_FLAGS) -o $@ -c $< 78 | 79 | traits_tests.o: traits_tests.cpp 80 | $(CXX) $(CU_INC) $(CU_FLAGS) $(CX_INC) $(CX_FLAGS) -o $@ -c $< 81 | 82 | tests.o: tests.cpp 83 | $(CXX) $(CU_INC) $(CU_FLAGS) $(CX_INC) $(CX_FLAGS) -o $@ -c $< 84 | 85 | build_tests: container_tests.o tensor_tests.o traits_tests.o operations_tests.o tests.o 86 | $(CXX) -o $(EXE) $+ $(CU_LDIR) $(CU_LIBS) $(CX_LDIR) $(CX_LIBS) 87 | 88 | container: CX_FLAGS += -DSTAND_ALONE 89 | container: container_tests.o 90 | $(CXX) -o $(CONTAINER_EXE) $+ $(CU_LDIR) $(CU_LIBS) $(CX_LDIR) $(CX_LIBS) 91 | 92 | operations: CX_FLAGS += -DSTAND_ALONE 93 | operations: operations_tests.o 94 | $(CXX) -o $(OPERATIONS_EXE) $+ $(CU_LDIR) $(CU_LIBS) $(CX_LDIR) $(CX_LIBS) 95 | 96 | tensor: CX_FLAGS += -DSTAND_ALONE 97 | tensor: tensor_tests.o 98 | $(CXX) -o $(TENSOR_EXE) $+ $(CU_LDIR) $(CU_LIBS) $(CX_LDIR) $(CX_LIBS) 99 | 100 | traits: CX_FLAGS += -DSTAND_ALONE 101 | traits: traits_tests.o 102 | $(CXX) -o $(TRAITS_EXE) $+ $(CU_LDIR) $(CU_LIBS) $(CX_LDIR) $(CX_LIBS) 103 | 104 | clean: 105 | rm -rf *.o 106 | rm -rf $(EXE) 107 | rm -rf $(CONTAINER_EXE) 108 | rm -rf $(OPERATIONS_EXE) 109 | rm -rf $(TENSOR_EXE) 110 | rm -rf $(TRAITS_EXE) 111 | -------------------------------------------------------------------------------- /tests/container_tests.cpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file container_tests.cpp 3 | /// @brief Test suites for container tests 4 | // ---------------------------------------------------------------------------------------------------------- 5 | 6 | #define BOOST_TEST_DYN_LINK 7 | #ifdef STAND_ALONE 8 | #define BOOST_TEST_MODULE ContainerTests 9 | #endif 10 | #include 11 | 12 | #ifndef FTL_TENSOR_CONTAINER_HPP 13 | #include "../tensor/tensor_container.hpp" 14 | #endif 15 | 16 | BOOST_AUTO_TEST_SUITE( TensorContainerSuite) 17 | 18 | // TODO: Add tests that conver entire container functionality 19 | 20 | BOOST_AUTO_TEST_CASE( canCreateStaticContainer ) 21 | { 22 | // Create a container specifying the dimension sizes 23 | ftl::TensorContainer A; 24 | 25 | BOOST_CHECK( A.size() == 6 ); 26 | } 27 | 28 | BOOST_AUTO_TEST_CASE( canCreateDynamicContainer ) 29 | { 30 | // Create a container without specifying the dimensions 31 | ftl::TensorContainer A; 32 | 33 | BOOST_CHECK( A.size() == 0 ); 34 | } 35 | 36 | BOOST_AUTO_TEST_SUITE_END() 37 | -------------------------------------------------------------------------------- /tests/operations_tests.cpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file operations_tests.cpp 3 | /// @brief Test suite for tensor operationstests 4 | // ---------------------------------------------------------------------------------------------------------- 5 | 6 | #define BOOST_TEST_DYN_LINK 7 | #ifdef STAND_ALONE 8 | #define BOOST_TEST_MODULE OperationsTests 9 | #endif 10 | #include 11 | 12 | #include "../tensor/tensor.hpp" 13 | #include "../tensor/tensor_operations.hpp" 14 | 15 | #include 16 | 17 | BOOST_AUTO_TEST_SUITE( OperationsSuite ) 18 | 19 | // -------------------------------------------- ADDITION --------------------------------------------------- 20 | 21 | BOOST_AUTO_TEST_CASE( canAdd2StaticTensors ) 22 | { 23 | ftl::Tensor A{ 1, 2, 3, 4 }; 24 | ftl::Tensor B{ 1, 2, 3, 4 }; 25 | 26 | auto C = A + B; 27 | ftl::Tensor D = A + B; 28 | 29 | BOOST_CHECK( C[0] == 2 ); 30 | BOOST_CHECK( D[0] == 2 ); 31 | BOOST_CHECK( C[1] == 4 ); 32 | BOOST_CHECK( D[1] == 4 ); 33 | BOOST_CHECK( C[2] == 6 ); 34 | BOOST_CHECK( D[2] == 6 ); 35 | BOOST_CHECK( C[3] == 8 ); 36 | BOOST_CHECK( D[3] == 8 ); 37 | } 38 | 39 | BOOST_AUTO_TEST_CASE( canAdd2DynamicTensors ) 40 | { 41 | // Create 2 dynamic tensors of rank 2 42 | // with dimension size of 2x2 43 | ftl::Tensor A{ 2, 2 }; 44 | ftl::Tensor B{ 2, 2 }; 45 | 46 | // Intialize A to have values of 1, and B to have values of 2 47 | A.initialize(1, 1); 48 | B.initialize(2, 2); 49 | 50 | auto C = A + B; 51 | ftl::Tensor D = A + B; 52 | 53 | BOOST_CHECK( C[0] == 3 ); 54 | BOOST_CHECK( D[0] == 3 ); 55 | BOOST_CHECK( C[1] == 3 ); 56 | BOOST_CHECK( D[1] == 3 ); 57 | BOOST_CHECK( C[2] == 3 ); 58 | BOOST_CHECK( D[2] == 3 ); 59 | BOOST_CHECK( C[3] == 3 ); 60 | BOOST_CHECK( D[3] == 3 ); 61 | } 62 | 63 | BOOST_AUTO_TEST_CASE( canAddAStaticAndDynamicTensorToGetAStaticTensor ) 64 | { 65 | ftl::Tensor A{ 1, 2, 3, 4 }; 66 | ftl::Tensor B{ 2, 2 }; 67 | 68 | // Initialize B with values of 10 69 | B.initialize(10, 10); 70 | 71 | // Addition takes the traits of the first tensor in the addition (A) 72 | // So C and D are static tensors since A is a static tensor 73 | auto C = A + B; 74 | ftl::Tensor D = A + B; 75 | 76 | BOOST_CHECK( C[0] == 11 ); 77 | BOOST_CHECK( D[0] == 11 ); 78 | BOOST_CHECK( C[1] == 12 ); 79 | BOOST_CHECK( D[1] == 12 ); 80 | BOOST_CHECK( C[2] == 13 ); 81 | BOOST_CHECK( D[2] == 13 ); 82 | BOOST_CHECK( C[3] == 14 ); 83 | BOOST_CHECK( D[3] == 14 ); 84 | 85 | } 86 | 87 | BOOST_AUTO_TEST_CASE( canAddADynamicAndStaticTensorToGetADynamicTensor ) 88 | { 89 | ftl::Tensor A{ 2, 2 }; 90 | ftl::Tensor B{ 1, 2, 3, 4 }; 91 | 92 | // Initialize A with values of 10 93 | A.initialize(10, 10); 94 | 95 | // Addition takes the traits of the first tensor in the addition (A) 96 | // So C and D are dynamic tensors since A is a dynamic tensor 97 | auto C = A + B; 98 | ftl::Tensor D = A + B; 99 | 100 | BOOST_CHECK( C[0] == 11 ); 101 | BOOST_CHECK( D[0] == 11 ); 102 | BOOST_CHECK( C[1] == 12 ); 103 | BOOST_CHECK( D[1] == 12 ); 104 | BOOST_CHECK( C[2] == 13 ); 105 | BOOST_CHECK( D[2] == 13 ); 106 | BOOST_CHECK( C[3] == 14 ); 107 | BOOST_CHECK( D[3] == 14 ); 108 | } 109 | 110 | // ---------------------------------------------- SUBTRACTION ----------------------------------------------- 111 | 112 | BOOST_AUTO_TEST_CASE( canSubtract2StaticTensors ) 113 | { 114 | // Tensor dimensions are stored down (col) then across (row) 115 | ftl::Tensor A{ 1, 2, 3, 4 }; 116 | ftl::Tensor B{ 2, 4, 6, 8 }; 117 | 118 | auto C = A - B; 119 | ftl::Tensor D = A - B; 120 | 121 | // Using auto makes a TensorSubtraction<...> which doesn't have 122 | // and overloaded () operator at present as the expression classes 123 | // are supposed to be used to create new tensors (as is done for D) 124 | BOOST_CHECK( C[0] == -1 ); 125 | BOOST_CHECK( D(0, 0) == -1 ); 126 | BOOST_CHECK( C[1] == -2 ); 127 | BOOST_CHECK( D(1, 0) == -2 ); 128 | BOOST_CHECK( C[2] == -3 ); 129 | BOOST_CHECK( D(0, 1) == -3 ); 130 | BOOST_CHECK( C[3] == -4 ); 131 | BOOST_CHECK( D(1, 1) == -4 ); 132 | } 133 | 134 | BOOST_AUTO_TEST_SUITE_END() 135 | -------------------------------------------------------------------------------- /tests/tensor_tests.cpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file tensor_tests.cpp 3 | /// @brief Test suite for tensor tests 4 | // ---------------------------------------------------------------------------------------------------------- 5 | 6 | #define BOOST_TEST_DYN_LINK 7 | #ifdef STAND_ALONE 8 | #define BOOST_TEST_MODULE TensorTests 9 | #endif 10 | #include 11 | 12 | #include "../tensor/tensor.hpp" 13 | #include "../tensor/tensor_operations.hpp" 14 | 15 | BOOST_AUTO_TEST_SUITE( TensorSuite) 16 | 17 | BOOST_AUTO_TEST_CASE( canCreateDynamicTensor ) 18 | { 19 | // Define the type of the dynamic tensor using the general tensor type 20 | using dynamic_tensor_gen = ftl::Tensor; 21 | 22 | // Define the type of the dynamic tensor using the specialized CPU definition 23 | using dynamic_tensor_cpu = ftl::DynamicTensorCpu; 24 | 25 | // Create a container using the traits class -- need to specify the rank of dynamic tensors 26 | dynamic_tensor_gen A(3); // Rank 3 tensor 27 | dynamic_tensor_cpu B(4); // Rank 4 tensor 28 | 29 | BOOST_CHECK( A.rank() == 3 ); 30 | BOOST_CHECK( B.rank() == 4 ); 31 | } 32 | 33 | BOOST_AUTO_TEST_CASE( canCreateDynamicTensorFromDimensionSizesAdnData ) 34 | { 35 | std::vector dimension_sizes = { 2 , 3 }; 36 | std::vector data = { 1.f, 2.f , // e00, xe, y0 37 | 3.f, 4.f , // x0, x1, y1 38 | 5.f, 6.f }; // x0, x1, y2 39 | 40 | // Use the data to create the tensor -- will have rank 2 41 | ftl::Tensor A(dimension_sizes, data); 42 | auto tensor_data = A.data(); 43 | 44 | BOOST_CHECK( A.size() == 6 ); 45 | BOOST_CHECK( A.rank() == 2 ); 46 | BOOST_CHECK( tensor_data[0] == 1.f ); 47 | BOOST_CHECK( tensor_data[1] == 2.f ); 48 | BOOST_CHECK( tensor_data[2] == 3.f ); 49 | BOOST_CHECK( tensor_data[3] == 4.f ); 50 | BOOST_CHECK( tensor_data[4] == 5.f ); 51 | BOOST_CHECK( tensor_data[5] == 6.f ); 52 | } 53 | 54 | BOOST_AUTO_TEST_CASE( canSetAndGetElementOfDynamicTensor ) 55 | { 56 | // Create a dynamic tensor specifying the sizes of the dimensions 57 | ftl::DynamicTensorCpu A( {3, 3, 3} ); 58 | 59 | // Set 2nd element 60 | A(1, 0, 0) = 4; 61 | 62 | BOOST_CHECK( A.size() == 27 ); 63 | BOOST_CHECK( A.rank() == 3 ); 64 | BOOST_CHECK( A(1, 0, 0) == 4 ); 65 | } 66 | 67 | BOOST_AUTO_TEST_CASE( canGetSizeOfASpecificDimensionOfADynamicTensor ) 68 | { 69 | ftl::Tensor A( {1, 2, 3} ); 70 | 71 | BOOST_CHECK( A.size(0) == 1 ); 72 | BOOST_CHECK( A.size(1) == 2 ); 73 | BOOST_CHECK( A.size(2) == 3 ); 74 | } 75 | 76 | // -------------------------------------------- STATIC CPU -------------------------------------------------- 77 | 78 | BOOST_AUTO_TEST_CASE( canCreateDefaultStaticTensor ) 79 | { 80 | // Define the type of the static tensor using the general tensor type 81 | // This defines a rank 3 tensor with all dimensions sizes with a value of 2 82 | using static_tensor_gen = ftl::Tensor; 83 | 84 | // Define the type of the static tensor using the specialized CPU definition 85 | // This defines a rank 3 tensor with all dimensions sizes with a value of 2 86 | using static_tensor_cpu = ftl::StaticTensorCpu; 87 | 88 | static_tensor_gen A; 89 | static_tensor_cpu B; 90 | 91 | auto dim_sizes_a = A.dim_sizes(); 92 | auto dim_sizes_b = B.dim_sizes(); 93 | 94 | BOOST_CHECK( A.size() == 8 ); 95 | BOOST_CHECK( B.size() == 8 ); 96 | BOOST_CHECK( A.rank() == 3 ); 97 | BOOST_CHECK( B.rank() == 3 ); 98 | BOOST_CHECK( B.size() == 8 ); 99 | BOOST_CHECK( dim_sizes_a[0] == 2 ); 100 | BOOST_CHECK( dim_sizes_a[1] == 2 ); 101 | BOOST_CHECK( dim_sizes_a[2] == 2 ); 102 | BOOST_CHECK( dim_sizes_b[0] == 2 ); 103 | BOOST_CHECK( dim_sizes_b[1] == 2 ); 104 | BOOST_CHECK( dim_sizes_b[2] == 2 ); 105 | } 106 | 107 | BOOST_AUTO_TEST_CASE( canCreateStaticTensorWithDataFromContainer ) 108 | { 109 | // Create data for the static tensor 110 | std::array data{ {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f} }; 111 | 112 | // Create a container specifying the dimension sizes 113 | ftl::Tensor A(data); 114 | 115 | BOOST_CHECK( A.size() == 6 ); 116 | BOOST_CHECK( A[0] == 1.0f ); 117 | BOOST_CHECK( A[1] == 2.0f ); 118 | BOOST_CHECK( A[2] == 3.0f ); 119 | BOOST_CHECK( A[3] == 4.0f ); 120 | BOOST_CHECK( A[4] == 5.0f ); 121 | BOOST_CHECK( A[5] == 6.0f ); 122 | } 123 | 124 | BOOST_AUTO_TEST_CASE( canCreateStaticTensorWithLiteralList ) 125 | { 126 | // Create a container specifying the dimension sizes 127 | ftl::Tensor A{ 1.0, 2.0, 3.0, 4.0 }; 128 | 129 | BOOST_CHECK( A.size() == 4 ); 130 | BOOST_CHECK( A[0] == 1.0 ); 131 | BOOST_CHECK( A[1] == 2.0 ); 132 | BOOST_CHECK( A[2] == 3.0 ); 133 | BOOST_CHECK( A[3] == 4.0 ); 134 | } 135 | 136 | BOOST_AUTO_TEST_CASE( canDetermineDimensionSizesCorrectly ) 137 | { 138 | std::array data{ 1.0, 2.0 }; 139 | 140 | // Create a container specifying the dimension sizes 141 | ftl::StaticTensorCpu A{ 1, 2, 3, 4 }; 142 | ftl::StaticTensorCpu B; 143 | ftl::StaticTensorCpu C(data); 144 | 145 | auto a_dim_sizes = A.dim_sizes(); 146 | auto b_dim_sizes = B.dim_sizes(); 147 | auto c_dim_sizes = C.dim_sizes(); 148 | 149 | BOOST_CHECK( a_dim_sizes[0] == 2 ); 150 | BOOST_CHECK( a_dim_sizes[1] == 2 ); 151 | BOOST_CHECK( b_dim_sizes[0] == 3 ); 152 | BOOST_CHECK( b_dim_sizes[1] == 3 ); 153 | BOOST_CHECK( c_dim_sizes[0] == 2 ); 154 | } 155 | 156 | BOOST_AUTO_TEST_CASE( canGetAndSetElementOfStaticTensor ) 157 | { 158 | ftl::Tensor A{4, 3, 2, 1}; 159 | 160 | // Set 2nd element of the tensor 161 | A(1, 0) = 12; 162 | 163 | // Get 2nd element of the tensor 164 | int element = A(1, 0); 165 | 166 | BOOST_CHECK( element == 12 ); 167 | } 168 | 169 | BOOST_AUTO_TEST_CASE( mappingOfMultipleDimensionsIsCorrect ) 170 | { 171 | // Create a tensor and fill it with some data. Data values are the indecies of the element 172 | // to show the mapping, however, 1 indexing is used since an integer value can't have leading 0's 173 | // so: 174 | // value 111 = indices 0, 0, 0 for dim 0, 1, 2 respecively 175 | // value 212 = indices 1, 0, 1 for dim 0, 1, 2 respectively 176 | ftl::StaticTensorCpu A{ 111, 211, 121, 221 , 177 | 112, 212, 122, 222 }; 178 | 179 | BOOST_CHECK( A(0, 1, 1) == 122 ); 180 | BOOST_CHECK( A(1, 0, 1) == 212 ); 181 | BOOST_CHECK( A(1, 1, 0) == 221 ); 182 | BOOST_CHECK( A(1, 0, 0) == 211 ); 183 | } 184 | 185 | BOOST_AUTO_TEST_CASE( canInitializeAStaticTensor ) 186 | { 187 | // Create a 2x2x2 tensor with initial value 188 | ftl::Tensor A{ 110, 120, 210, 220, 111, 121, 211, 221 }; 189 | 190 | // Modify all values by initializing them all to 1 191 | A.initialize(1, 1); 192 | 193 | BOOST_CHECK( A(0, 0, 0) == 1 ); 194 | } 195 | 196 | BOOST_AUTO_TEST_CASE( canGetSizeOfASpecificDimensionOfAStaticTensor ) 197 | { 198 | ftl::Tensor A; 199 | 200 | BOOST_CHECK( A.size(0) == 1 ); 201 | BOOST_CHECK( A.size(1) == 2 ); 202 | BOOST_CHECK( A.size(2) == 3 ); 203 | } 204 | BOOST_AUTO_TEST_SUITE_END() 205 | -------------------------------------------------------------------------------- /tests/tests.cpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file tests.cpp 3 | /// @brief Test suite for all tests 4 | // ---------------------------------------------------------------------------------------------------------- 5 | 6 | #define BOOST_TEST_DYN_LINK 7 | #define BOOST_TEST_MODULE TensorTests 8 | #include 9 | -------------------------------------------------------------------------------- /tests/traits_tests.cpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------- 2 | /// @file traits_tests.cpp 3 | /// @brief Test suite for traits tests 4 | // ---------------------------------------------------------------------------------------------------------- 5 | 6 | #define BOOST_TEST_DYN_LINK 7 | #ifdef STAND_ALONE 8 | #define BOOST_TEST_MODULE TraitsTests 9 | #endif 10 | #include 11 | 12 | #include "../tensor/tensor_traits.hpp" 13 | 14 | BOOST_AUTO_TEST_SUITE( TensorTraitsSuite) 15 | 16 | BOOST_AUTO_TEST_CASE( canDetermineStaticContainerFromTraits ) 17 | { 18 | // Define traits for tensor 19 | // : int data type 20 | // : cpu implementation 21 | // : dimension sizes of 2 and 3 22 | using traits = ftl::TensorTraits; 23 | 24 | // Create a container using the traits class 25 | traits::container_type A; 26 | 27 | BOOST_CHECK( A.size() == 6 ); 28 | } 29 | 30 | BOOST_AUTO_TEST_SUITE_END() 31 | --------------------------------------------------------------------------------