├── .gitignore ├── LICENSE ├── README.md ├── assets ├── final_1.jpg ├── final_2.png ├── md5_1.png ├── summary_1.png └── trap_1.png ├── final ├── final.md ├── input1.txt ├── input2.txt ├── input3.txt ├── input4.txt ├── input5.txt ├── input6.txt ├── openmp_CYK.cpp ├── serial_CYK.cpp └── summary.md ├── lab1 ├── lab1.md └── pi.c ├── lab2 ├── lab2.md ├── lib │ ├── md5.c │ ├── md5.h │ └── md5driver.c └── md5.c ├── lab3 ├── integral.c └── lab3.md ├── lab4 ├── histogram.c └── lab4.md └── pdf ├── Chapter_1.pdf ├── Chapter_2.pdf ├── Chapter_3.pdf ├── Chapter_4.pdf ├── Chapter_5.pdf ├── Chapter_6.pdf └── Chapter_7.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | a.exe 2 | a.out 3 | test.cpp 4 | input.txt 5 | final.exe 6 | serial.exe 7 | .vscode 8 | openmp_CYK.s -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Qin Zhou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parallel Programming 2 | 3 | ## 介绍 4 | 5 | 本仓库是北航软件学院**并行程序设计**课程的 Lab 合集以及课件合集,代码均由本人独自完成,最终竞速Rank1 6 | 7 | 该课程一共有 **7** 个 Chapter,按顺序分别讲解了使用 MPI、Pthread、OpenMP、CUDA 进行**并行计算**的方法,并在课程中贯穿了并行程序设计的基础思想 8 | 9 | 该课程一共有 **5** 个 Lab,要求使用 MPI、Pthread、OpenMP 等实现特定的程序,最后一个 Lab 为**竞速**大作业 10 | 11 | ## Labs 12 | 13 | [Lab1](./lab1/lab1.md): 使用 **MPI** 加速计算 PI 的蒙特卡罗方法 14 | 15 | [Lab2](./lab2/lab2.md): 使用 **MPI** 暴力求解 md5 算法的原文 16 | 17 | [Lab3](./lab3/lab3.md): 使用 **Pthread** 实现梯形积分法,要求分别使用信号量、互斥锁、忙等待实现同步 18 | 19 | [Lab4](./lab4/lab4.md): 使用 **OpenMP** 加速计算数据直方图的统计 20 | 21 | [Final](./final/final.md): 基于 CYK 算法,计算一个字符串所能产生的语法树的数量,**加速方法不限** 22 | 23 | ## 感想 24 | 25 | 该课程的任课教师是软院的邵兵老师,不得不说邵老师上课确实幽默风趣、尽职尽责 26 | 27 | **上课**印象最深的是邵老师上课突然点到我,但我当时在看 C++ Primer 而且看不清幕布上的代码,导致问题答不上来(bushi 28 | 29 | **课下**印象最深的是对竞速大作业的优化,其实还有很多可以优化的地方,比如再卡一卡缓存、再把一些小循环放在外层、自适应调整算法... 30 | 31 | 最后的竞速大作业,我有幸拿下 Rank1,不得不说确实高兴了好一会( 32 | 33 | ## 其他 34 | 35 | 本仓库使用 MIT 协议,在使用本仓库的资源时,请注明原作者以及本仓库的位置 36 | 37 | 欢迎参观[我的个人博客](https://matrix53.github.io) 38 | -------------------------------------------------------------------------------- /assets/final_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/assets/final_1.jpg -------------------------------------------------------------------------------- /assets/final_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/assets/final_2.png -------------------------------------------------------------------------------- /assets/md5_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/assets/md5_1.png -------------------------------------------------------------------------------- /assets/summary_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/assets/summary_1.png -------------------------------------------------------------------------------- /assets/trap_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/assets/trap_1.png -------------------------------------------------------------------------------- /final/final.md: -------------------------------------------------------------------------------- 1 | ## 问题描述 2 | 3 | CYK 算法(Cocke–Younger–Kasami algorithm,缩写为 CYK algorithm)是由约翰·科克、Younger 和嵩忠雄共同研究出来大约发表于 1965 年的一个算法,它是一个用来判定任意给定的字符串 w 是否属于一个上下文无关文法的算法。普通的回溯法在最坏的情况下需要指数时间才能解决这样的问题,而 CYK 算法只需要多项式时间就够了(O(n^3), n 为字符串 w 的长度)。CYK 算法采用了动态规划的思想,其伪代码描述如下: 4 | 5 | ![final_1.jpg](../assets/final_1.jpg) 6 | 7 | 本大作业提供了串行代码与数据样例,请同学们在串行代码的基础上完成代码并行化。 8 | 9 | 串行代码仅供参考,也可以自己编写效率更高的串行代码,成绩同样有效。 10 | 11 | 不要尝试修改算法,因为编译原理课上讲的算法不能处理二义性文法,测试用例给定的文法都是有二义性的上下文无关文法。 12 | 13 | 不可对文法进行化简,这会导致结果不正确。 14 | 15 | ## 输入形式 16 | 17 | 从"input.txt"读入 18 | 19 | 第一行是一个整型,表示非终结符的数量 vn_num 20 | 21 | 第二行是一个整型,表示“右侧是两个非终结符的产生式”的数量 production2_num,即代码中的 Production2 类型的数量 22 | 23 | 接下来 production2_num 行,每行是一个 Production2 类型,非终结符的格式是"<%d>",数字范围是 0 到(production2_num-1),"<0>"表示开始符号 24 | 25 | 然后下一行是一个整型,表示“右侧是一个终结符的产生式”的数量 production1_num,即代码中的 Production1 类型的数量 26 | 27 | 接下来 production1_num 行,每行是一个 Production1 类型,终结符的格式是"%c",范围是所有可打印的 ASCII 字符 28 | 29 | 然后下一行是一个整型,表示被测试的字符串的长度 30 | 31 | 最后一行是被测试的字符串 32 | 33 | ## 输出形式 34 | 35 | 一个 32 位无符号整型,表示被测试的字符串能构成多少棵符合文法的语法树,语法树的数量可能很多,为了简单起见,若发生溢出就截取低 32 位 36 | 37 | ## 输入样例 38 | 39 | ``` 40 | 4 41 | 5 42 | <0>::=<1><2> 43 | <0>::=<2><3> 44 | <1>::=<2><1> 45 | <2>::=<3><3> 46 | <3>::=<1><2> 47 | 3 48 | <1>::=a 49 | <2>::=b 50 | <3>::=a 51 | 5 52 | baaba 53 | ``` 54 | 55 | ## 输出样例 56 | 57 | ``` 58 | 2 59 | ``` 60 | 61 | ## 样例说明 62 | 63 | 输入样例中的文法和字符串可以构成两棵语法树,如图所示: 64 | 65 | ![final_2.png](../assets/final_2.png) 66 | -------------------------------------------------------------------------------- /final/input1.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 5 3 | <0>::=<1><2> 4 | <0>::=<2><3> 5 | <1>::=<2><1> 6 | <2>::=<3><3> 7 | <3>::=<1><2> 8 | 3 9 | <1>::=a 10 | <2>::=b 11 | <3>::=a 12 | 5 13 | baaba -------------------------------------------------------------------------------- /final/input2.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 25 3 | <0>::=<1><2> 4 | <0>::=<2><6> 5 | <0>::=<7><1> 6 | <0>::=<5><8> 7 | <1>::=<4><7> 8 | <1>::=<3><2> 9 | <1>::=<2><9> 10 | <1>::=<3><1> 11 | <2>::=<8><8> 12 | <2>::=<1><5> 13 | <2>::=<7><2> 14 | <2>::=<2><9> 15 | <3>::=<3><1> 16 | <3>::=<9><3> 17 | <3>::=<6><2> 18 | <4>::=<8><6> 19 | <4>::=<2><9> 20 | <5>::=<3><1> 21 | <5>::=<9><3> 22 | <6>::=<8><7> 23 | <6>::=<3><2> 24 | <7>::=<6><3> 25 | <7>::=<3><1> 26 | <8>::=<4><6> 27 | <9>::=<3><7> 28 | 9 29 | <1>::=a 30 | <2>::=b 31 | <3>::=c 32 | <4>::=b 33 | <5>::=a 34 | <6>::=a 35 | <7>::=d 36 | <8>::=e 37 | <9>::=f 38 | 765 39 | cbccbabaedcabdbdbccafcabcdcbedbabbfdafbfcedcafcebafabaccebbedcaabfbaeaabcbddefbfeddababcbacafccbbbcacbcddccacabbcbfacacdcbdcfcadbcbffabfcaaeceeabaaeefbcdbfcbabcbcadeacaacaaacbcaccabfaacabcaacbeddcaabbcaafabdbaaeaccababfffaddbafbcacacbdacdcaebafebafdcacaacccbcfcceecdeeaffcadbccdabbacdebedabcaccafccbabffcadaebedcdbbafcabccaaaaabfcdabaacaccbcdcacdbfcabbfcaebfaddfcabcbfcbcdffcaadfcabcabfaabfcaababcaacdcddcbdaabfceebffcaaacbababeacbabcfcbdcbdbccaafccaaaaacdaccdccdcbdcaacbfabcaaabccbccaccdcabedbcbbfadccdaebcadacacabdbacdfcabcffcbffcacbdecaabeddbaccdaaabcaabedbffccdbabcdacbceeccafcbcdfcdccdccfabacbfabcddcafffcdcacbafceedadcabcbebccbabebfcebedaacaaaceeaabbfcaadbcaaccbdcbccbaaaabaeaacdaffcbcacacffccdcbcdcbcacabaffcbfaafacdcbfcadbabaacbfdccccadbffffcacdbbcaafdfcaba -------------------------------------------------------------------------------- /final/input3.txt: -------------------------------------------------------------------------------- 1 | 4 2 | 5 3 | <0>::=<1><2> 4 | <0>::=<2><3> 5 | <1>::=<2><1> 6 | <2>::=<3><3> 7 | <3>::=<1><2> 8 | 3 9 | <1>::=a 10 | <2>::=b 11 | <3>::=a 12 | 6 13 | baabaa -------------------------------------------------------------------------------- /final/input4.txt: -------------------------------------------------------------------------------- 1 | 128 2 | 512 3 | <0>::=<7><7> 4 | <0>::=<9><3> 5 | <0>::=<10><6> 6 | <0>::=<10><13> 7 | <0>::=<11><2> 8 | <0>::=<11><7> 9 | <0>::=<12><8> 10 | <0>::=<13><15> 11 | <0>::=<22><36> 12 | <1>::=<6><7> 13 | <1>::=<11><0> 14 | <1>::=<12><0> 15 | <1>::=<119><55> 16 | <2>::=<1><3> 17 | <2>::=<8><4> 18 | <2>::=<15><11> 19 | <2>::=<18><104> 20 | <3>::=<0><0> 21 | <3>::=<10><12> 22 | <3>::=<41><122> 23 | <4>::=<12><14> 24 | <4>::=<63><75> 25 | <5>::=<1><7> 26 | <5>::=<8><28> 27 | <5>::=<10><5> 28 | <5>::=<15><12> 29 | <6>::=<5><14> 30 | <6>::=<6><9> 31 | <6>::=<9><1> 32 | <6>::=<9><15> 33 | <6>::=<11><7> 34 | <6>::=<12><13> 35 | <6>::=<81><14> 36 | <7>::=<11><0> 37 | <7>::=<12><6> 38 | <7>::=<99><56> 39 | <8>::=<0><2> 40 | <8>::=<1><13> 41 | <8>::=<10><7> 42 | <8>::=<106><5> 43 | <9>::=<2><11> 44 | <9>::=<85><109> 45 | <10>::=<90><46> 46 | <11>::=<2><7> 47 | <11>::=<10><1> 48 | <11>::=<10><9> 49 | <11>::=<12><14> 50 | <11>::=<33><41> 51 | <12>::=<6><7> 52 | <12>::=<9><5> 53 | <12>::=<61><69> 54 | <13>::=<5><6> 55 | <13>::=<5><9> 56 | <13>::=<12><0> 57 | <13>::=<40><94> 58 | <14>::=<0><3> 59 | <14>::=<23><14> 60 | <15>::=<11><4> 61 | <15>::=<12><14> 62 | <15>::=<114><7> 63 | <16>::=<0><6> 64 | <16>::=<1><5> 65 | <16>::=<119><12> 66 | <17>::=<5><14> 67 | <17>::=<5><65> 68 | <17>::=<12><7> 69 | <18>::=<0><10> 70 | <18>::=<6><0> 71 | <18>::=<8><3> 72 | <18>::=<10><1> 73 | <18>::=<48><112> 74 | <19>::=<8><4> 75 | <19>::=<11><11> 76 | <19>::=<12><0> 77 | <19>::=<86><13> 78 | <20>::=<5><10> 79 | <20>::=<5><94> 80 | <20>::=<10><8> 81 | <21>::=<5><14> 82 | <21>::=<15><7> 83 | <21>::=<15><8> 84 | <21>::=<26><56> 85 | <22>::=<1><6> 86 | <22>::=<12><11> 87 | <22>::=<15><9> 88 | <22>::=<58><111> 89 | <23>::=<3><8> 90 | <23>::=<17><77> 91 | <24>::=<2><2> 92 | <24>::=<8><2> 93 | <24>::=<11><8> 94 | <24>::=<91><41> 95 | <25>::=<46><62> 96 | <26>::=<6><11> 97 | <26>::=<8><13> 98 | <26>::=<11><2> 99 | <26>::=<15><5> 100 | <26>::=<112><15> 101 | <27>::=<1><7> 102 | <27>::=<6><1> 103 | <27>::=<6><4> 104 | <27>::=<11><10> 105 | <27>::=<13><4> 106 | <27>::=<14><8> 107 | <27>::=<63><3> 108 | <28>::=<3><4> 109 | <28>::=<21><72> 110 | <29>::=<3><9> 111 | <29>::=<83><95> 112 | <30>::=<0><5> 113 | <30>::=<8><9> 114 | <30>::=<51><1> 115 | <31>::=<0><4> 116 | <31>::=<8><4> 117 | <31>::=<12><6> 118 | <31>::=<30><101> 119 | <32>::=<0><0> 120 | <32>::=<1><4> 121 | <32>::=<51><68> 122 | <33>::=<0><4> 123 | <33>::=<7><2> 124 | <33>::=<12><10> 125 | <33>::=<65><69> 126 | <34>::=<0><13> 127 | <34>::=<8><9> 128 | <34>::=<8><12> 129 | <34>::=<13><13> 130 | <34>::=<72><24> 131 | <35>::=<0><6> 132 | <35>::=<2><1> 133 | <35>::=<3><3> 134 | <35>::=<10><3> 135 | <35>::=<14><2> 136 | <35>::=<80><47> 137 | <36>::=<0><13> 138 | <36>::=<5><6> 139 | <36>::=<7><8> 140 | <36>::=<7><10> 141 | <36>::=<9><7> 142 | <36>::=<11><7> 143 | <36>::=<11><10> 144 | <36>::=<47><41> 145 | <37>::=<2><6> 146 | <37>::=<3><3> 147 | <37>::=<8><10> 148 | <37>::=<14><8> 149 | <38>::=<14><3> 150 | <38>::=<63><100> 151 | <39>::=<1><6> 152 | <39>::=<4><10> 153 | <39>::=<11><2> 154 | <39>::=<13><2> 155 | <39>::=<13><3> 156 | <39>::=<44><40> 157 | <40>::=<1><3> 158 | <40>::=<7><5> 159 | <40>::=<120><78> 160 | <41>::=<3><15> 161 | <41>::=<8><7> 162 | <41>::=<8><14> 163 | <41>::=<76><122> 164 | <42>::=<1><8> 165 | <42>::=<2><6> 166 | <42>::=<11><10> 167 | <42>::=<13><10> 168 | <42>::=<72><48> 169 | <43>::=<0><1> 170 | <43>::=<7><13> 171 | <43>::=<7><14> 172 | <43>::=<9><5> 173 | <43>::=<10><0> 174 | <43>::=<10><8> 175 | <43>::=<21><123> 176 | <44>::=<1><12> 177 | <44>::=<12><4> 178 | <44>::=<14><7> 179 | <45>::=<3><15> 180 | <45>::=<4><5> 181 | <45>::=<12><4> 182 | <45>::=<25><119> 183 | <46>::=<0><6> 184 | <46>::=<11><13> 185 | <46>::=<123><107> 186 | <47>::=<127><88> 187 | <48>::=<1><7> 188 | <48>::=<3><8> 189 | <48>::=<10><2> 190 | <48>::=<10><13> 191 | <48>::=<111><4> 192 | <49>::=<2><7> 193 | <49>::=<12><10> 194 | <49>::=<65><91> 195 | <50>::=<2><8> 196 | <50>::=<8><0> 197 | <50>::=<12><8> 198 | <50>::=<12><15> 199 | <50>::=<13><11> 200 | <50>::=<50><9> 201 | <51>::=<0><2> 202 | <51>::=<1><14> 203 | <51>::=<5><2> 204 | <51>::=<6><9> 205 | <51>::=<13><3> 206 | <51>::=<14><1> 207 | <51>::=<107><92> 208 | <52>::=<2><0> 209 | <52>::=<3><7> 210 | <52>::=<4><14> 211 | <52>::=<102><25> 212 | <53>::=<12><15> 213 | <53>::=<103><8> 214 | <54>::=<2><1> 215 | <54>::=<6><11> 216 | <54>::=<11><7> 217 | <54>::=<13><125> 218 | <55>::=<13><12> 219 | <55>::=<112><49> 220 | <56>::=<12><2> 221 | <56>::=<30><46> 222 | <57>::=<2><4> 223 | <57>::=<5><1> 224 | <57>::=<10><7> 225 | <57>::=<13><2> 226 | <57>::=<13><13> 227 | <57>::=<58><50> 228 | <58>::=<7><15> 229 | <58>::=<15><10> 230 | <58>::=<15><11> 231 | <58>::=<102><23> 232 | <59>::=<50><19> 233 | <60>::=<7><7> 234 | <60>::=<81><32> 235 | <61>::=<2><8> 236 | <61>::=<7><0> 237 | <61>::=<12><4> 238 | <61>::=<13><3> 239 | <61>::=<13><5> 240 | <61>::=<14><1> 241 | <61>::=<72><46> 242 | <62>::=<0><7> 243 | <62>::=<1><0> 244 | <62>::=<3><15> 245 | <62>::=<5><6> 246 | <62>::=<12><2> 247 | <62>::=<15><13> 248 | <62>::=<59><106> 249 | <63>::=<11><12> 250 | <63>::=<15><11> 251 | <63>::=<31><77> 252 | <64>::=<1><12> 253 | <64>::=<2><9> 254 | <64>::=<3><1> 255 | <64>::=<13><0> 256 | <64>::=<13><9> 257 | <64>::=<112><114> 258 | <65>::=<3><12> 259 | <65>::=<9><12> 260 | <65>::=<22><93> 261 | <66>::=<6><4> 262 | <66>::=<6><15> 263 | <66>::=<48><78> 264 | <67>::=<2><14> 265 | <67>::=<7><8> 266 | <67>::=<7><13> 267 | <67>::=<7><15> 268 | <67>::=<25><112> 269 | <68>::=<85><91> 270 | <69>::=<4><5> 271 | <69>::=<8><9> 272 | <69>::=<117><37> 273 | <70>::=<4><3> 274 | <70>::=<13><9> 275 | <70>::=<14><12> 276 | <70>::=<45><82> 277 | <71>::=<2><1> 278 | <71>::=<3><14> 279 | <71>::=<9><4> 280 | <71>::=<11><9> 281 | <71>::=<13><7> 282 | <71>::=<117><25> 283 | <72>::=<4><0> 284 | <72>::=<7><13> 285 | <72>::=<11><7> 286 | <72>::=<15><7> 287 | <72>::=<95><115> 288 | <73>::=<6><8> 289 | <73>::=<11><12> 290 | <73>::=<15><11> 291 | <73>::=<26><27> 292 | <74>::=<3><12> 293 | <74>::=<103><33> 294 | <75>::=<0><15> 295 | <75>::=<2><2> 296 | <75>::=<7><8> 297 | <75>::=<8><4> 298 | <75>::=<13><7> 299 | <75>::=<13><8> 300 | <75>::=<14><6> 301 | <75>::=<89><120> 302 | <76>::=<3><15> 303 | <76>::=<4><2> 304 | <76>::=<4><13> 305 | <76>::=<6><12> 306 | <76>::=<7><10> 307 | <76>::=<7><11> 308 | <76>::=<122><1> 309 | <77>::=<0><12> 310 | <77>::=<1><7> 311 | <77>::=<8><0> 312 | <77>::=<11><3> 313 | <77>::=<12><1> 314 | <77>::=<72><29> 315 | <78>::=<7><1> 316 | <78>::=<12><3> 317 | <78>::=<87><106> 318 | <79>::=<0><0> 319 | <79>::=<9><2> 320 | <79>::=<23><29> 321 | <80>::=<2><12> 322 | <80>::=<31><86> 323 | <81>::=<1><12> 324 | <81>::=<3><14> 325 | <81>::=<8><8> 326 | <81>::=<8><14> 327 | <81>::=<67><60> 328 | <82>::=<7><4> 329 | <82>::=<11><1> 330 | <82>::=<11><4> 331 | <82>::=<13><2> 332 | <82>::=<39><5> 333 | <83>::=<0><14> 334 | <83>::=<8><13> 335 | <83>::=<83><20> 336 | <84>::=<1><5> 337 | <84>::=<3><7> 338 | <84>::=<5><13> 339 | <84>::=<14><7> 340 | <84>::=<14><13> 341 | <84>::=<110><30> 342 | <85>::=<2><0> 343 | <85>::=<8><0> 344 | <85>::=<11><2> 345 | <85>::=<13><13> 346 | <85>::=<14><12> 347 | <85>::=<14><81> 348 | <85>::=<15><8> 349 | <86>::=<0><12> 350 | <86>::=<6><2> 351 | <86>::=<6><3> 352 | <86>::=<15><1> 353 | <86>::=<15><2> 354 | <86>::=<27><42> 355 | <87>::=<0><11> 356 | <87>::=<9><9> 357 | <87>::=<11><6> 358 | <87>::=<90><43> 359 | <88>::=<3><15> 360 | <88>::=<7><13> 361 | <88>::=<8><1> 362 | <88>::=<12><7> 363 | <88>::=<14><1> 364 | <88>::=<14><9> 365 | <88>::=<15><5> 366 | <88>::=<47><78> 367 | <89>::=<4><6> 368 | <89>::=<12><10> 369 | <89>::=<14><14> 370 | <89>::=<72><62> 371 | <90>::=<1><4> 372 | <90>::=<1><7> 373 | <90>::=<12><4> 374 | <90>::=<78><89> 375 | <91>::=<5><9> 376 | <91>::=<10><11> 377 | <91>::=<11><3> 378 | <91>::=<37><63> 379 | <92>::=<4><2> 380 | <92>::=<8><15> 381 | <92>::=<10><0> 382 | <92>::=<10><7> 383 | <92>::=<115><127> 384 | <93>::=<12><14> 385 | <93>::=<14><8> 386 | <93>::=<85><120> 387 | <94>::=<1><1> 388 | <94>::=<3><0> 389 | <94>::=<5><12> 390 | <94>::=<8><0> 391 | <94>::=<10><13> 392 | <94>::=<13><12> 393 | <94>::=<44><107> 394 | <95>::=<0><14> 395 | <95>::=<8><123> 396 | <95>::=<9><9> 397 | <95>::=<12><2> 398 | <96>::=<6><12> 399 | <96>::=<12><0> 400 | <96>::=<42><113> 401 | <97>::=<6><1> 402 | <97>::=<9><9> 403 | <97>::=<30><62> 404 | <98>::=<4><9> 405 | <98>::=<15><8> 406 | <98>::=<127><87> 407 | <99>::=<3><13> 408 | <99>::=<9><8> 409 | <99>::=<9><15> 410 | <99>::=<32><46> 411 | <100>::=<91><60> 412 | <101>::=<4><4> 413 | <101>::=<5><1> 414 | <101>::=<6><1> 415 | <101>::=<11><10> 416 | <101>::=<15><10> 417 | <101>::=<127><24> 418 | <102>::=<3><0> 419 | <102>::=<3><14> 420 | <102>::=<10><5> 421 | <102>::=<14><10> 422 | <102>::=<69><117> 423 | <103>::=<2><5> 424 | <103>::=<2><80> 425 | <103>::=<5><7> 426 | <103>::=<11><13> 427 | <104>::=<10><15> 428 | <104>::=<29><2> 429 | <105>::=<0><1> 430 | <105>::=<3><6> 431 | <105>::=<5><14> 432 | <105>::=<6><2> 433 | <105>::=<24><86> 434 | <106>::=<1><7> 435 | <106>::=<7><14> 436 | <106>::=<10><6> 437 | <106>::=<15><10> 438 | <106>::=<15><15> 439 | <106>::=<23><24> 440 | <107>::=<1><11> 441 | <107>::=<9><11> 442 | <107>::=<94><5> 443 | <108>::=<4><13> 444 | <108>::=<8><4> 445 | <108>::=<11><1> 446 | <108>::=<14><10> 447 | <108>::=<48><11> 448 | <109>::=<4><7> 449 | <109>::=<5><11> 450 | <109>::=<12><8> 451 | <109>::=<14><12> 452 | <109>::=<89><48> 453 | <110>::=<4><11> 454 | <110>::=<48><47> 455 | <111>::=<3><10> 456 | <111>::=<9><15> 457 | <111>::=<38><68> 458 | <112>::=<6><7> 459 | <112>::=<10><9> 460 | <112>::=<11><86> 461 | <112>::=<14><0> 462 | <113>::=<15><9> 463 | <113>::=<24><18> 464 | <114>::=<9><15> 465 | <114>::=<14><15> 466 | <114>::=<124><123> 467 | <115>::=<3><43> 468 | <115>::=<5><2> 469 | <115>::=<14><13> 470 | <116>::=<1><4> 471 | <116>::=<2><5> 472 | <116>::=<79><43> 473 | <117>::=<4><0> 474 | <117>::=<7><2> 475 | <117>::=<10><0> 476 | <117>::=<15><8> 477 | <117>::=<32><55> 478 | <118>::=<8><4> 479 | <118>::=<10><12> 480 | <118>::=<11><10> 481 | <118>::=<83><38> 482 | <119>::=<0><6> 483 | <119>::=<15><4> 484 | <119>::=<59><58> 485 | <120>::=<5><12> 486 | <120>::=<7><11> 487 | <120>::=<10><7> 488 | <120>::=<110><50> 489 | <121>::=<1><4> 490 | <121>::=<8><1> 491 | <121>::=<22><56> 492 | <122>::=<1><2> 493 | <122>::=<6><50> 494 | <122>::=<7><15> 495 | <122>::=<14><0> 496 | <123>::=<2><2> 497 | <123>::=<11><12> 498 | <123>::=<12><4> 499 | <123>::=<89><108> 500 | <124>::=<1><9> 501 | <124>::=<6><0> 502 | <124>::=<12><4> 503 | <124>::=<14><83> 504 | <125>::=<0><4> 505 | <125>::=<10><10> 506 | <125>::=<88><90> 507 | <126>::=<2><11> 508 | <126>::=<4><14> 509 | <126>::=<7><4> 510 | <126>::=<49><91> 511 | <127>::=<3><5> 512 | <127>::=<4><0> 513 | <127>::=<15><8> 514 | <127>::=<28><88> 515 | 128 516 | <0>::=m 517 | <0>::=n 518 | <1>::=i 519 | <1>::=o 520 | <1>::=r 521 | <3>::=o 522 | <3>::=z 523 | <4>::=w 524 | <5>::=c 525 | <7>::=i 526 | <8>::=c 527 | <10>::=r 528 | <11>::=e 529 | <11>::=q 530 | <13>::=r 531 | <15>::=p 532 | <16>::=h 533 | <17>::=f 534 | <17>::=s 535 | <19>::=c 536 | <19>::=j 537 | <22>::=h 538 | <23>::=q 539 | <24>::=w 540 | <27>::=z 541 | <29>::=b 542 | <29>::=w 543 | <30>::=i 544 | <31>::=b 545 | <32>::=b 546 | <32>::=o 547 | <33>::=i 548 | <33>::=o 549 | <34>::=g 550 | <34>::=v 551 | <37>::=t 552 | <39>::=r 553 | <40>::=o 554 | <40>::=z 555 | <41>::=n 556 | <41>::=y 557 | <42>::=a 558 | <43>::=i 559 | <43>::=j 560 | <43>::=r 561 | <44>::=x 562 | <45>::=e 563 | <45>::=s 564 | <46>::=a 565 | <46>::=i 566 | <47>::=i 567 | <48>::=d 568 | <48>::=m 569 | <49>::=s 570 | <50>::=c 571 | <51>::=x 572 | <52>::=y 573 | <53>::=z 574 | <55>::=d 575 | <55>::=i 576 | <56>::=k 577 | <62>::=a 578 | <62>::=b 579 | <64>::=c 580 | <64>::=l 581 | <64>::=s 582 | <65>::=m 583 | <65>::=w 584 | <65>::=z 585 | <66>::=l 586 | <67>::=e 587 | <67>::=r 588 | <67>::=u 589 | <68>::=p 590 | <69>::=d 591 | <69>::=i 592 | <70>::=h 593 | <72>::=d 594 | <72>::=e 595 | <72>::=y 596 | <73>::=d 597 | <78>::=f 598 | <81>::=z 599 | <82>::=x 600 | <84>::=a 601 | <84>::=s 602 | <84>::=v 603 | <86>::=s 604 | <88>::=j 605 | <88>::=q 606 | <89>::=t 607 | <90>::=d 608 | <90>::=o 609 | <90>::=r 610 | <91>::=q 611 | <92>::=f 612 | <92>::=j 613 | <93>::=m 614 | <94>::=n 615 | <94>::=o 616 | <94>::=y 617 | <95>::=k 618 | <97>::=a 619 | <97>::=l 620 | <97>::=x 621 | <101>::=g 622 | <101>::=m 623 | <102>::=u 624 | <104>::=w 625 | <106>::=a 626 | <106>::=y 627 | <107>::=c 628 | <107>::=l 629 | <109>::=x 630 | <110>::=f 631 | <111>::=g 632 | <111>::=o 633 | <115>::=g 634 | <117>::=b 635 | <117>::=h 636 | <117>::=n 637 | <118>::=a 638 | <118>::=w 639 | <119>::=i 640 | <120>::=f 641 | <122>::=v 642 | <126>::=j 643 | <126>::=z 644 | 319 645 | czweacpieorpercdoqrzimzewiizywqweencwrcivdqqocqocmoieiimiyoirwrorricqmomwqccieownzmwdrrrinomzmyvzqmoqnxcklrcmzprroqzyainkhiyczwprrperoiriwrnvercrobcweccpcrccwqiiozxomwcowicnormrpqerpewcicimimwaornmdawerpepqciowrcroiqnzrcczwomdmznwnonwqpcmpeqprcwpceroxpicrcqeqqcbcnpcxrcocooepozrcqckoiirdmcrrrxiriizycrcdpzmoidirwnxrmwen -------------------------------------------------------------------------------- /final/input5.txt: -------------------------------------------------------------------------------- 1 | 128 2 | 512 3 | <0>::=<4><24> 4 | <0>::=<13><1> 5 | <0>::=<123><52> 6 | <1>::=<2><27> 7 | <1>::=<10><13> 8 | <1>::=<23><4> 9 | <1>::=<31><31> 10 | <1>::=<100><16> 11 | <2>::=<24><27> 12 | <2>::=<27><2> 13 | <2>::=<82><34> 14 | <3>::=<3><19> 15 | <3>::=<69><64> 16 | <4>::=<0><26> 17 | <4>::=<2><0> 18 | <4>::=<24><5> 19 | <4>::=<24><24> 20 | <4>::=<109><78> 21 | <5>::=<3><69> 22 | <5>::=<15><17> 23 | <5>::=<16><24> 24 | <6>::=<3><0> 25 | <6>::=<6><25> 26 | <6>::=<7><6> 27 | <6>::=<36><53> 28 | <7>::=<11><4> 29 | <7>::=<11><22> 30 | <7>::=<24><24> 31 | <7>::=<37><92> 32 | <8>::=<2><5> 33 | <8>::=<14><15> 34 | <8>::=<16><25> 35 | <8>::=<23><1> 36 | <8>::=<23><25> 37 | <8>::=<101><104> 38 | <9>::=<2><2> 39 | <9>::=<4><10> 40 | <9>::=<12><8> 41 | <9>::=<21><24> 42 | <9>::=<77><51> 43 | <10>::=<20><15> 44 | <10>::=<24><3> 45 | <10>::=<100><42> 46 | <11>::=<2><6> 47 | <11>::=<18><30> 48 | <11>::=<19><2> 49 | <11>::=<27><16> 50 | <11>::=<103><76> 51 | <12>::=<11><30> 52 | <12>::=<13><31> 53 | <12>::=<18><15> 54 | <12>::=<58><105> 55 | <13>::=<3><97> 56 | <13>::=<21><3> 57 | <13>::=<25><30> 58 | <14>::=<23><15> 59 | <15>::=<2><27> 60 | <15>::=<4><8> 61 | <15>::=<10><6> 62 | <15>::=<21><20> 63 | <15>::=<43><4> 64 | <16>::=<16><17> 65 | <16>::=<18><23> 66 | <16>::=<53><114> 67 | <17>::=<3><31> 68 | <17>::=<6><28> 69 | <17>::=<9><31> 70 | <17>::=<10><19> 71 | <17>::=<12><18> 72 | <17>::=<25><4> 73 | <17>::=<71><37> 74 | <18>::=<0><13> 75 | <18>::=<4><20> 76 | <18>::=<5><3> 77 | <18>::=<17><5> 78 | <18>::=<22><14> 79 | <18>::=<22><27> 80 | <18>::=<123><16> 81 | <19>::=<18><10> 82 | <19>::=<42><96> 83 | <20>::=<8><31> 84 | <20>::=<10><22> 85 | <20>::=<11><6> 86 | <20>::=<14><1> 87 | <20>::=<21><1> 88 | <20>::=<101><115> 89 | <21>::=<30><18> 90 | <21>::=<56><15> 91 | <22>::=<1><21> 92 | <22>::=<6><4> 93 | <22>::=<18><89> 94 | <22>::=<30><19> 95 | <23>::=<11><24> 96 | <23>::=<18><4> 97 | <23>::=<30><14> 98 | <23>::=<38><69> 99 | <24>::=<23><9> 100 | <24>::=<31><31> 101 | <24>::=<35><55> 102 | <25>::=<5><8> 103 | <25>::=<127><1> 104 | <26>::=<27><26> 105 | <26>::=<29><10> 106 | <26>::=<35><71> 107 | <27>::=<13><21> 108 | <27>::=<14><11> 109 | <27>::=<37><51> 110 | <28>::=<17><24> 111 | <28>::=<19><27> 112 | <28>::=<78><73> 113 | <29>::=<8><23> 114 | <29>::=<16><18> 115 | <29>::=<22><26> 116 | <29>::=<109><61> 117 | <30>::=<3><31> 118 | <30>::=<11><32> 119 | <30>::=<30><19> 120 | <31>::=<8><20> 121 | <31>::=<20><14> 122 | <31>::=<27><19> 123 | <31>::=<31><22> 124 | <31>::=<32><73> 125 | <32>::=<15><6> 126 | <32>::=<27><15> 127 | <32>::=<68><32> 128 | <33>::=<97><33> 129 | <34>::=<3><11> 130 | <34>::=<91><14> 131 | <35>::=<3><57> 132 | <35>::=<29><21> 133 | <36>::=<3><5> 134 | <36>::=<9><3> 135 | <36>::=<9><67> 136 | <36>::=<12><5> 137 | <36>::=<21><1> 138 | <36>::=<27><31> 139 | <37>::=<6><68> 140 | <37>::=<13><3> 141 | <37>::=<23><2> 142 | <38>::=<4><12> 143 | <38>::=<24><22> 144 | <38>::=<29><10> 145 | <38>::=<68><85> 146 | <39>::=<112><67> 147 | <40>::=<0><11> 148 | <40>::=<2><7> 149 | <40>::=<2><13> 150 | <40>::=<3><21> 151 | <40>::=<4><30> 152 | <40>::=<13><26> 153 | <40>::=<16><23> 154 | <40>::=<18><2> 155 | <40>::=<19><12> 156 | <40>::=<23><28> 157 | <41>::=<3><2> 158 | <41>::=<21><19> 159 | <41>::=<59><13> 160 | <42>::=<5><13> 161 | <42>::=<19><2> 162 | <42>::=<25><8> 163 | <42>::=<27><24> 164 | <42>::=<30><12> 165 | <42>::=<36><30> 166 | <43>::=<17><12> 167 | <43>::=<19><30> 168 | <43>::=<23><30> 169 | <43>::=<119><95> 170 | <44>::=<16><99> 171 | <44>::=<30><26> 172 | <45>::=<29><19> 173 | <45>::=<66><62> 174 | <46>::=<32><16> 175 | <47>::=<9><9> 176 | <47>::=<13><4> 177 | <47>::=<120><120> 178 | <48>::=<11><31> 179 | <48>::=<15><19> 180 | <48>::=<28><15> 181 | <49>::=<15><17> 182 | <49>::=<16><25> 183 | <49>::=<17><9> 184 | <49>::=<24><18> 185 | <49>::=<30><46> 186 | <50>::=<0><20> 187 | <50>::=<1><31> 188 | <50>::=<3><21> 189 | <50>::=<5><2> 190 | <50>::=<9><10> 191 | <50>::=<72><90> 192 | <51>::=<13><10> 193 | <51>::=<23><10> 194 | <51>::=<72><106> 195 | <52>::=<18><1> 196 | <52>::=<20><31> 197 | <52>::=<24><22> 198 | <52>::=<24><25> 199 | <52>::=<31><17> 200 | <52>::=<45><101> 201 | <53>::=<0><14> 202 | <53>::=<14><24> 203 | <53>::=<15><30> 204 | <53>::=<18><20> 205 | <53>::=<98><89> 206 | <54>::=<30><6> 207 | <54>::=<70><55> 208 | <55>::=<14><25> 209 | <55>::=<16><30> 210 | <55>::=<20><2> 211 | <56>::=<0><6> 212 | <56>::=<7><55> 213 | <56>::=<11><10> 214 | <57>::=<2><12> 215 | <57>::=<3><18> 216 | <57>::=<10><13> 217 | <57>::=<24><9> 218 | <57>::=<25><3> 219 | <57>::=<25><9> 220 | <57>::=<101><66> 221 | <58>::=<6><3> 222 | <58>::=<12><2> 223 | <58>::=<12><27> 224 | <58>::=<19><18> 225 | <58>::=<31><16> 226 | <58>::=<96><74> 227 | <59>::=<15><8> 228 | <59>::=<28><6> 229 | <59>::=<38><103> 230 | <60>::=<9><2> 231 | <60>::=<12><18> 232 | <60>::=<14><19> 233 | <60>::=<17><7> 234 | <60>::=<22><4> 235 | <60>::=<101><60> 236 | <61>::=<4><31> 237 | <61>::=<17><7> 238 | <61>::=<28><16> 239 | <61>::=<58><52> 240 | <62>::=<0><7> 241 | <62>::=<10><11> 242 | <62>::=<19><23> 243 | <62>::=<28><11> 244 | <62>::=<66><53> 245 | <63>::=<11><31> 246 | <63>::=<16><5> 247 | <63>::=<24><16> 248 | <63>::=<28><14> 249 | <63>::=<29><29> 250 | <63>::=<34><89> 251 | <64>::=<29><25> 252 | <64>::=<122><66> 253 | <65>::=<56><62> 254 | <66>::=<1><20> 255 | <66>::=<6><30> 256 | <66>::=<7><22> 257 | <66>::=<14><12> 258 | <66>::=<114><51> 259 | <67>::=<12><82> 260 | <68>::=<4><3> 261 | <68>::=<75><120> 262 | <69>::=<8><32> 263 | <69>::=<19><25> 264 | <69>::=<30><0> 265 | <70>::=<11><20> 266 | <70>::=<16><30> 267 | <70>::=<24><5> 268 | <70>::=<61><73> 269 | <71>::=<18><3> 270 | <71>::=<21><21> 271 | <71>::=<22><31> 272 | <71>::=<25><8> 273 | <71>::=<30><24> 274 | <71>::=<98><80> 275 | <72>::=<8><29> 276 | <72>::=<11><18> 277 | <72>::=<11><21> 278 | <72>::=<20><6> 279 | <72>::=<21><10> 280 | <72>::=<94><108> 281 | <73>::=<8><26> 282 | <73>::=<12><8> 283 | <73>::=<12><69> 284 | <73>::=<14><18> 285 | <74>::=<2><3> 286 | <74>::=<3><16> 287 | <74>::=<3><28> 288 | <74>::=<6><4> 289 | <74>::=<14><6> 290 | <74>::=<19><20> 291 | <74>::=<21><22> 292 | <74>::=<105><2> 293 | <75>::=<6><2> 294 | <75>::=<6><18> 295 | <75>::=<16><19> 296 | <75>::=<43><22> 297 | <76>::=<0><30> 298 | <76>::=<9><28> 299 | <76>::=<28><29> 300 | <76>::=<70><86> 301 | <77>::=<20><90> 302 | <77>::=<21><5> 303 | <77>::=<24><5> 304 | <77>::=<25><7> 305 | <77>::=<28><25> 306 | <78>::=<4><15> 307 | <78>::=<5><4> 308 | <78>::=<7><7> 309 | <78>::=<91><38> 310 | <79>::=<6><9> 311 | <79>::=<19><14> 312 | <79>::=<28><1> 313 | <79>::=<34><47> 314 | <80>::=<29><22> 315 | <80>::=<86><43> 316 | <81>::=<0><9> 317 | <81>::=<6><18> 318 | <81>::=<14><22> 319 | <81>::=<116><115> 320 | <82>::=<10><0> 321 | <82>::=<23><6> 322 | <82>::=<31><11> 323 | <82>::=<67><122> 324 | <83>::=<13><116> 325 | <83>::=<22><5> 326 | <84>::=<26><5> 327 | <84>::=<27><13> 328 | <84>::=<31><20> 329 | <85>::=<2><5> 330 | <85>::=<11><1> 331 | <85>::=<31><21> 332 | <85>::=<34><125> 333 | <86>::=<7><24> 334 | <86>::=<25><30> 335 | <86>::=<105><16> 336 | <87>::=<15><15> 337 | <87>::=<28><31> 338 | <87>::=<120><61> 339 | <88>::=<5><17> 340 | <88>::=<19><17> 341 | <88>::=<27><7> 342 | <88>::=<50><100> 343 | <89>::=<2><18> 344 | <89>::=<21><13> 345 | <89>::=<106><18> 346 | <90>::=<1><19> 347 | <90>::=<6><16> 348 | <90>::=<10><22> 349 | <90>::=<20><24> 350 | <90>::=<24><6> 351 | <90>::=<31><32> 352 | <91>::=<17><11> 353 | <91>::=<66><56> 354 | <92>::=<2><31> 355 | <92>::=<6><16> 356 | <92>::=<12><14> 357 | <92>::=<16><19> 358 | <92>::=<30><20> 359 | <92>::=<77><1> 360 | <93>::=<19><14> 361 | <93>::=<22><3> 362 | <93>::=<25><24> 363 | <94>::=<1><26> 364 | <94>::=<5><17> 365 | <94>::=<8><6> 366 | <94>::=<23><6> 367 | <94>::=<31><12> 368 | <94>::=<112><94> 369 | <95>::=<0><24> 370 | <95>::=<2><24> 371 | <95>::=<13><12> 372 | <95>::=<23><28> 373 | <95>::=<27><3> 374 | <95>::=<95><14> 375 | <96>::=<2><2> 376 | <96>::=<2><101> 377 | <96>::=<19><0> 378 | <96>::=<19><16> 379 | <96>::=<20><20> 380 | <97>::=<6><21> 381 | <97>::=<10><9> 382 | <97>::=<107><92> 383 | <98>::=<10><26> 384 | <98>::=<23><9> 385 | <98>::=<24><4> 386 | <98>::=<69><37> 387 | <99>::=<1><31> 388 | <99>::=<8><12> 389 | <99>::=<14><9> 390 | <99>::=<59><35> 391 | <100>::=<13><27> 392 | <100>::=<19><16> 393 | <100>::=<24><29> 394 | <100>::=<40><61> 395 | <101>::=<17><7> 396 | <101>::=<17><25> 397 | <101>::=<21><8> 398 | <101>::=<50><42> 399 | <102>::=<2><15> 400 | <102>::=<3><8> 401 | <102>::=<5><5> 402 | <102>::=<5><16> 403 | <102>::=<25><11> 404 | <102>::=<70><81> 405 | <103>::=<9><13> 406 | <103>::=<21><28> 407 | <103>::=<22><30> 408 | <103>::=<24><19> 409 | <103>::=<31><27> 410 | <103>::=<65><115> 411 | <104>::=<2><6> 412 | <104>::=<11><15> 413 | <104>::=<12><25> 414 | <104>::=<17><10> 415 | <104>::=<125><85> 416 | <105>::=<9><28> 417 | <105>::=<29><124> 418 | <106>::=<29><27> 419 | <106>::=<65><29> 420 | <107>::=<5><7> 421 | <107>::=<9><24> 422 | <107>::=<11><23> 423 | <107>::=<13><20> 424 | <107>::=<29><3> 425 | <107>::=<34><51> 426 | <108>::=<6><23> 427 | <108>::=<6><29> 428 | <108>::=<28><17> 429 | <108>::=<50><101> 430 | <109>::=<7><2> 431 | <109>::=<16><4> 432 | <109>::=<29><3> 433 | <109>::=<103><113> 434 | <110>::=<8><18> 435 | <110>::=<10><4> 436 | <110>::=<23><26> 437 | <111>::=<0><4> 438 | <111>::=<0><22> 439 | <111>::=<26><1> 440 | <111>::=<38><32> 441 | <112>::=<20><6> 442 | <112>::=<26><27> 443 | <112>::=<30><23> 444 | <112>::=<42><35> 445 | <113>::=<1><2> 446 | <113>::=<2><27> 447 | <113>::=<7><28> 448 | <113>::=<10><27> 449 | <113>::=<22><10> 450 | <113>::=<28><19> 451 | <113>::=<28><27> 452 | <113>::=<114><89> 453 | <114>::=<2><26> 454 | <114>::=<16><28> 455 | <114>::=<16><115> 456 | <115>::=<20><0> 457 | <115>::=<26><5> 458 | <115>::=<54><97> 459 | <116>::=<1><18> 460 | <116>::=<10><30> 461 | <116>::=<13><5> 462 | <116>::=<25><1> 463 | <116>::=<27><11> 464 | <116>::=<30><5> 465 | <116>::=<58><92> 466 | <117>::=<1><6> 467 | <117>::=<2><4> 468 | <117>::=<3><16> 469 | <117>::=<24><23> 470 | <117>::=<29><21> 471 | <117>::=<78><119> 472 | <118>::=<3><26> 473 | <118>::=<4><105> 474 | <118>::=<13><13> 475 | <119>::=<12><20> 476 | <119>::=<72><114> 477 | <120>::=<8><15> 478 | <120>::=<15><11> 479 | <120>::=<23><26> 480 | <121>::=<0><29> 481 | <121>::=<13><22> 482 | <121>::=<25><4> 483 | <121>::=<28><22> 484 | <121>::=<81><92> 485 | <122>::=<0><13> 486 | <122>::=<20><13> 487 | <122>::=<30><12> 488 | <122>::=<74><5> 489 | <123>::=<4><6> 490 | <123>::=<4><10> 491 | <123>::=<6><22> 492 | <123>::=<19><13> 493 | <123>::=<100><6> 494 | <124>::=<11><4> 495 | <124>::=<14><19> 496 | <124>::=<15><13> 497 | <124>::=<18><8> 498 | <125>::=<11><1> 499 | <125>::=<13><13> 500 | <125>::=<23><31> 501 | <125>::=<59><33> 502 | <126>::=<3><29> 503 | <126>::=<4><13> 504 | <126>::=<10><13> 505 | <126>::=<15><25> 506 | <126>::=<25><13> 507 | <126>::=<30><31> 508 | <127>::=<1><9> 509 | <127>::=<3><28> 510 | <127>::=<13><8> 511 | <127>::=<15><24> 512 | <127>::=<24><0> 513 | <127>::=<24><11> 514 | <127>::=<112><71> 515 | 128 516 | <0>::=d 517 | <1>::=r 518 | <2>::=g 519 | <4>::=k 520 | <5>::=y 521 | <6>::=q 522 | <6>::=u 523 | <8>::=q 524 | <10>::=g 525 | <13>::=a 526 | <14>::=s 527 | <15>::=c 528 | <15>::=e 529 | <16>::=m 530 | <16>::=n 531 | <17>::=l 532 | <18>::=t 533 | <19>::=h 534 | <20>::=m 535 | <20>::=y 536 | <22>::=h 537 | <23>::=q 538 | <24>::=q 539 | <25>::=s 540 | <26>::=e 541 | <28>::=w 542 | <29>::=u 543 | <30>::=k 544 | <30>::=n 545 | <31>::=n 546 | <35>::=o 547 | <35>::=p 548 | <37>::=a 549 | <37>::=f 550 | <38>::=n 551 | <40>::=c 552 | <40>::=j 553 | <40>::=u 554 | <42>::=a 555 | <43>::=d 556 | <43>::=h 557 | <44>::=i 558 | <44>::=k 559 | <44>::=t 560 | <44>::=w 561 | <46>::=b 562 | <46>::=f 563 | <46>::=o 564 | <48>::=x 565 | <49>::=c 566 | <49>::=m 567 | <50>::=j 568 | <53>::=z 569 | <54>::=f 570 | <54>::=j 571 | <56>::=f 572 | <56>::=m 573 | <56>::=x 574 | <57>::=d 575 | <58>::=e 576 | <59>::=e 577 | <59>::=m 578 | <60>::=m 579 | <61>::=f 580 | <61>::=k 581 | <62>::=s 582 | <64>::=m 583 | <64>::=q 584 | <65>::=a 585 | <65>::=w 586 | <66>::=k 587 | <66>::=q 588 | <68>::=r 589 | <69>::=d 590 | <69>::=i 591 | <69>::=j 592 | <69>::=o 593 | <71>::=q 594 | <72>::=x 595 | <74>::=i 596 | <76>::=e 597 | <77>::=a 598 | <77>::=o 599 | <81>::=e 600 | <82>::=g 601 | <82>::=p 602 | <82>::=v 603 | <87>::=l 604 | <88>::=x 605 | <89>::=a 606 | <89>::=j 607 | <89>::=p 608 | <89>::=z 609 | <91>::=p 610 | <93>::=p 611 | <93>::=z 612 | <94>::=h 613 | <96>::=f 614 | <97>::=x 615 | <99>::=i 616 | <99>::=u 617 | <101>::=p 618 | <102>::=a 619 | <104>::=i 620 | <107>::=u 621 | <107>::=x 622 | <108>::=i 623 | <108>::=o 624 | <108>::=q 625 | <109>::=w 626 | <112>::=c 627 | <113>::=f 628 | <113>::=v 629 | <114>::=z 630 | <119>::=z 631 | <121>::=o 632 | <122>::=i 633 | <122>::=l 634 | <122>::=m 635 | <122>::=o 636 | <123>::=p 637 | <124>::=l 638 | <125>::=v 639 | <126>::=c 640 | <126>::=g 641 | <127>::=i 642 | <127>::=x 643 | <127>::=z 644 | 854 645 | aaxemntnhnlomdkxesyefhkimhtkdzgontzrntdmhgqqkhxqcfaggxqkgqeaqnjqygjiaumtjdqhdiqyafxfdaqsqtgwqqaktomwemqekhqiqhhhgqnkpngnnskneqanqceheleljeklnqdjqafckaavoqaktspnkgqgakanaagdmhqaqyqyqapssqdsksnanyzaqsqhnhqeqoqamcomguakyomhuqymahprnqnydmhsqdmafqmsramcecskimtghaqggeaznsmmcyhnaxntaanyomhmfqgeqcgphsqheitkqomqeksshkskypzznthfimqykgmnqrqftghafqrkpksltnnyoqhhaxqumnntaoyqqmdqhhgafgahdelmomafhamqtntagkafgafxcxeqykkghcqstnedqggushfpyqafxkqxrjkdfjmqqqqqumdcqgusknpnhwhpqtwwkkkmrkfmagngphyqqcaeeaohaqgoqsaaftqxafmhqqomktgpkqccqqaxuxyafmzznahdkteikxjmafnthooafenlmqcnktrkthhtqtxcmqntannsafghkhszaktyqnrwgfhanmsumeqwqnnseqkszugmekycqmeehxcppsfqnuwqxqrklyqfcyqqqggstjnexufomxgfxqkfktqmsqyqkhxcqhsjqnnsanqsdqheoqnlsstgnnaqqdqgjqtghtghnqcujqsajxnhemgtmzhnimhhgimhgaxahfndgennagdqkhsyehhghssetoqkimrcqtcoueqlqqgajmxgdqcsagfedmnosqghdqhuxtkqkxhgnpiycstnairkiusskgmeqoagmq -------------------------------------------------------------------------------- /final/input6.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 25 3 | <0>::=<1><2> 4 | <0>::=<2><6> 5 | <0>::=<7><1> 6 | <0>::=<5><8> 7 | <1>::=<4><7> 8 | <1>::=<3><2> 9 | <1>::=<2><9> 10 | <1>::=<3><1> 11 | <2>::=<8><8> 12 | <2>::=<1><5> 13 | <2>::=<7><2> 14 | <2>::=<2><9> 15 | <3>::=<3><1> 16 | <3>::=<9><3> 17 | <3>::=<6><2> 18 | <4>::=<8><6> 19 | <4>::=<2><9> 20 | <5>::=<3><1> 21 | <5>::=<9><3> 22 | <6>::=<8><7> 23 | <6>::=<3><2> 24 | <7>::=<6><3> 25 | <7>::=<3><1> 26 | <8>::=<4><6> 27 | <9>::=<3><7> 28 | 9 29 | <1>::=a 30 | <2>::=b 31 | <3>::=c 32 | <4>::=b 33 | <5>::=a 34 | <6>::=a 35 | <7>::=d 36 | <8>::=e 37 | <9>::=f 38 | 765 39 | cbccbabaedcabdbdbccafcabcdcbedbabbfdafbfcedcafcebafabaccebbedcaabfbaeaabcbddefbfeddababcbacafccbbbcacbcddccacabbcbfacacdcbdcfcadbcbffabfcaaeceeabaaeefbcdbfcbabcbcadeacaacaaacbcaccabfaacabcaacbeddcaabbcaafabdbaaeaccababfffaddbafbcacacbdacdcaebafebafdcacaacccbcfcceecdeeaffcadbccdabbacdebedabcaccafccbabffcadaebedcdbbafcabccaaaaabfcdabaacaccbcdcacdbfcabbfcaebfaddfcabcbfcbcdffcaadfcabcabfaabfcaababcaacdcddcbdaabfceebffcaaacbababeacbabcfcbdcbdbccaafccaaaaacdaccdccdcbdcaacbfabcaaabccbccaccdcabedbcbbfadccdaebcadacacabdbacdfcabcffcbffcacbdecaabeddbaccdaaabcaabedbffccdbabcdacbceeccafcbcdfcdccdccfabacbfabcddcafffcdcacbafceedadcabcbebccbabebfcebedaacaaaceeaabbfcaadbcaaccbdcbccbaaaabaeaacdaffcbcacacffccdcbcdcbcacabaffcbfaafacdcbfcadbabaacbfdccccadbffffcacdbbcaafdfcaba -------------------------------------------------------------------------------- /final/openmp_CYK.cpp: -------------------------------------------------------------------------------- 1 | // 最终的目标机是16核的,测试用例为4,5,6号用例 2 | #pragma GCC optimize("Ofast") 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | const int MAX_PRODUCTION2_NUM = 512; 11 | const int MAX_PRODUCTION1_NUM = 128; 12 | const int MAX_VN = 128; 13 | const int MAX_VT = 128; 14 | const int MAX_SLEN = 1024; 15 | const int MAX_SINGLE_PRODUNCTION2 = 24; 16 | const int MAX_VN_SMALL = 10; 17 | 18 | typedef struct Production1 { 19 | int parent; 20 | int child; 21 | } Production1; 22 | typedef struct Production2 { 23 | int parent; 24 | int child1; 25 | int child2; 26 | } Production2; 27 | typedef struct Interval { 28 | int end; 29 | int len; 30 | } Interval; 31 | 32 | int vn_num, p2_num, p1_num, slen; 33 | Production2 p2[MAX_PRODUCTION2_NUM]; 34 | Production1 p1[MAX_PRODUCTION1_NUM]; 35 | char str[MAX_SLEN]; 36 | 37 | // 区间 [i, j] 由非终结符到情况总数的映射 38 | int dp[MAX_SLEN][MAX_SLEN][MAX_VN]; 39 | // 整理Production2,提高空间局部性,用数组手写vector 40 | int p22[MAX_VN][MAX_SINGLE_PRODUNCTION2]; 41 | 42 | // 解决旧版本GCC的OpenMP和optimize编译选项冲突的问题,详情见https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82374 43 | void omp_for_1(int index) { 44 | // 枚举所有Production1 45 | for (int k = 0; k < p1_num; ++k) { 46 | if (str[index] == p1[k].child) { 47 | dp[index][index][p1[k].parent] = 1; 48 | } 49 | } 50 | } 51 | void omp_for_2(int len, int start) { 52 | int end = start + len - 1; 53 | for (int mid = start; mid < end; ++mid) { 54 | // 枚举所有Production2 55 | for (int i = 0; i < vn_num; ++i) { 56 | int sum = 0; 57 | for (int j = 1; j < p22[i][0]; j += 2) { 58 | sum += dp[start][mid][p22[i][j]] * dp[mid + 1][end][p22[i][j + 1]]; 59 | } 60 | dp[start][end][i] += sum; 61 | } 62 | } 63 | } 64 | 65 | // 对于结果总数较小的情况,进行按需计算 66 | // 将Production2的两个child,映射到Production2的index范围 67 | Interval c2i[MAX_VN][MAX_VN]; 68 | // 区间 [i, j] 可以由哪些非终结符推导出来,这里用数组手写vector 69 | int vn_set[MAX_SLEN][MAX_SLEN][MAX_VN + 5]; 70 | 71 | void omp_for_3(int index) { 72 | unsigned long long bs[2] = {0, 0}; // 用数组手写bitset 73 | // 枚举所有Production1 74 | for (int k = 0; k < p1_num; ++k) { 75 | if (str[index] == p1[k].child) { 76 | dp[index][index][p1[k].parent] = 1; 77 | bs[p1[k].parent >> 6] |= 1llu << p1[k].parent; 78 | } 79 | } 80 | for (int i = 0; i < vn_num; ++i) { 81 | if (bs[i >> 6] >> i & 1) 82 | vn_set[index][index][++vn_set[index][index][0]] = i; 83 | } 84 | } 85 | void omp_for_4(int len, int start) { 86 | unsigned long long bs[2] = {0, 0}; // 用数组手写bitset 87 | int end = start + len - 1; 88 | for (int mid = start; mid < end; ++mid) { 89 | // 按需计算,组合出所有可能的结果 90 | for (int i = 1; i <= vn_set[start][mid][0]; ++i) { 91 | int vn1 = vn_set[start][mid][i]; 92 | for (int j = 1; j <= vn_set[mid + 1][end][0]; ++j) { 93 | int vn2 = vn_set[mid + 1][end][j]; 94 | int right = c2i[vn1][vn2].end; 95 | int left = right - c2i[vn1][vn2].len; 96 | for (int k = right; k > left; --k) { 97 | dp[start][end][p2[k].parent] += 98 | dp[start][mid][p2[k].child1] * dp[mid + 1][end][p2[k].child2]; 99 | bs[p2[k].parent >> 6] |= 1llu << p2[k].parent; 100 | } 101 | } 102 | } 103 | } 104 | for (int i = 0; i < vn_num; ++i) { 105 | if (bs[i >> 6] >> i & 1) vn_set[start][end][++vn_set[start][end][0]] = i; 106 | } 107 | } 108 | 109 | // s代表small,适用于vn_num较小的情况 110 | // 区间 [i, j] 由非终结符到情况总数的映射 111 | int dps[MAX_SLEN][MAX_SLEN][MAX_VN_SMALL]; 112 | // 整理Production2,提高空间局部性,用数组手写vector 113 | int p22s[MAX_VN_SMALL][MAX_SINGLE_PRODUNCTION2]; 114 | 115 | void omp_for_5(int index) { 116 | // 枚举所有Production1 117 | for (int k = 0; k < p1_num; ++k) { 118 | if (str[index] == p1[k].child) { 119 | dps[index][index][p1[k].parent] = 1; 120 | } 121 | } 122 | } 123 | void omp_for_6(int len, int start) { 124 | int end = start + len - 1; 125 | for (int mid = start; mid < end; ++mid) { 126 | // 枚举所有Production2 127 | for (int i = 0; i < vn_num; ++i) { 128 | int sum = 0; 129 | for (int j = 1; j < p22s[i][0]; j += 2) { 130 | sum += dps[start][mid][p22s[i][j]] * dps[mid + 1][end][p22s[i][j + 1]]; 131 | } 132 | dps[start][end][i] += sum; 133 | } 134 | } 135 | } 136 | 137 | int main() { 138 | // 计时开始 139 | steady_clock::time_point t1 = steady_clock::now(); 140 | 141 | freopen("input.txt", "r", stdin); 142 | scanf("%d\n", &vn_num); 143 | scanf("%d\n", &p2_num); 144 | for (int i = 0; i < p2_num; i++) 145 | scanf("<%d>::=<%d><%d>\n", &p2[i].parent, &p2[i].child1, &p2[i].child2); 146 | scanf("%d\n", &p1_num); 147 | for (int i = 0; i < p1_num; i++) 148 | scanf("<%d>::=%c\n", &p1[i].parent, &p1[i].child); 149 | scanf("%d\n", &slen); 150 | scanf("%s\n", str); 151 | 152 | if (vn_num <= 10) { 153 | // 重新整理Production2 154 | for (int i = 0; i < p2_num; ++i) { 155 | p22s[p2[i].parent][++p22s[p2[i].parent][0]] = p2[i].child1; 156 | p22s[p2[i].parent][++p22s[p2[i].parent][0]] = p2[i].child2; 157 | } 158 | 159 | // dp之前的必要初始化 160 | #pragma omp parallel for schedule(dynamic, 8) 161 | for (int i = 0; i < slen; ++i) { 162 | omp_for_5(i); 163 | } 164 | 165 | // 区间 dp 166 | for (int len = 2; len <= slen; ++len) { 167 | #pragma omp parallel for schedule(dynamic) 168 | for (int start = 0; start <= slen - len; ++start) { 169 | omp_for_6(len, start); 170 | } 171 | } 172 | 173 | // 计时结束 174 | steady_clock::time_point t2 = steady_clock::now(); 175 | duration time_span = duration_cast>(t2 - t1); 176 | printf("Total Time: %fs\n", time_span.count()); 177 | 178 | // 输出结果 179 | printf("%u\n", dps[0][slen - 1][0]); 180 | } else if (slen < 500) { 181 | // 重新整理Production2 182 | for (int i = 0; i < p2_num; ++i) { 183 | p22[p2[i].parent][++p22[p2[i].parent][0]] = p2[i].child1; 184 | p22[p2[i].parent][++p22[p2[i].parent][0]] = p2[i].child2; 185 | } 186 | 187 | // dp之前的必要初始化 188 | #pragma omp parallel for schedule(dynamic, 8) 189 | for (int i = 0; i < slen; ++i) { 190 | omp_for_1(i); 191 | } 192 | 193 | // 区间 dp 194 | for (int len = 2; len <= slen; ++len) { 195 | #pragma omp parallel for schedule(dynamic) 196 | for (int start = 0; start <= slen - len; ++start) { 197 | omp_for_2(len, start); 198 | } 199 | } 200 | 201 | // 计时结束 202 | steady_clock::time_point t2 = steady_clock::now(); 203 | duration time_span = duration_cast>(t2 - t1); 204 | printf("Total Time: %fs\n", time_span.count()); 205 | 206 | // 输出结果 207 | printf("%u\n", dp[0][slen - 1][0]); 208 | } else { 209 | // TODO 并行优化,对Production2进行排序 210 | sort(p2, p2 + p2_num, [](const Production2& a, const Production2& b) { 211 | if (a.child1 != b.child1) 212 | return a.child1 < b.child1; 213 | else if (a.child2 != b.child2) 214 | return a.child2 < b.child2; 215 | else 216 | return a.parent < b.parent; 217 | }); 218 | 219 | // 预处理出Production2的chlid2index 220 | for (int i = 0; i < p2_num; ++i) { 221 | c2i[p2[i].child1][p2[i].child2].end = i; 222 | c2i[p2[i].child1][p2[i].child2].len++; 223 | } 224 | 225 | // dp之前的必要初始化 226 | #pragma omp parallel for schedule(dynamic, 8) 227 | for (int i = 0; i < slen; ++i) { 228 | omp_for_3(i); 229 | } 230 | 231 | // 区间 dp 232 | for (int len = 2; len <= slen; ++len) { 233 | #pragma omp parallel for schedule(dynamic) 234 | for (int start = 0; start <= slen - len; ++start) { 235 | omp_for_4(len, start); 236 | } 237 | } 238 | 239 | // 计时结束 240 | steady_clock::time_point t2 = steady_clock::now(); 241 | duration time_span = duration_cast>(t2 - t1); 242 | printf("Total Time: %fs\n", time_span.count()); 243 | 244 | // 输出结果 245 | printf("%u\n", dp[0][slen - 1][0]); 246 | } 247 | return 0; 248 | } -------------------------------------------------------------------------------- /final/serial_CYK.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define MAX_PRODUCTION2_NUM 512 10 | #define MAX_PRODUCTION1_NUM 128 11 | #define MAX_VN_NUM 128 12 | #define MAX_VT_NUM 128 13 | #define MAX_STRING_LENGTH 1024 14 | 15 | struct BeginAndNum 16 | { 17 | int begin; 18 | unsigned num; 19 | }; 20 | 21 | struct Production2 22 | { 23 | int parent; 24 | int child1; 25 | int child2; 26 | } production2[MAX_PRODUCTION2_NUM]; 27 | 28 | struct Production1 29 | { 30 | int parent; 31 | char child; 32 | } production1[MAX_PRODUCTION1_NUM]; 33 | 34 | BeginAndNum vnIndex[MAX_VN_NUM][MAX_VN_NUM]; 35 | BeginAndNum vtIndex[MAX_VT_NUM]; 36 | 37 | char str[MAX_STRING_LENGTH]; 38 | 39 | struct SubTree 40 | { 41 | int root; 42 | unsigned num; 43 | } subTreeTable[MAX_STRING_LENGTH][MAX_STRING_LENGTH][MAX_VN_NUM]; 44 | 45 | int subTreeNumTable[MAX_STRING_LENGTH][MAX_STRING_LENGTH]; 46 | 47 | int vn_num; 48 | int production2_num; 49 | int production1_num; 50 | int string_length; 51 | 52 | int main() 53 | { 54 | freopen("input.txt", "r", stdin); 55 | scanf("%d\n", &vn_num); 56 | scanf("%d\n", &production2_num); 57 | for (int i = 0; i < production2_num; i++) 58 | scanf("<%d>::=<%d><%d>\n", &production2[i].parent, &production2[i].child1, &production2[i].child2); 59 | scanf("%d\n", &production1_num); 60 | for (int i = 0; i < production1_num; i++) 61 | scanf("<%d>::=%c\n", &production1[i].parent, &production1[i].child); 62 | scanf("%d\n", &string_length); 63 | scanf("%s\n", str); 64 | 65 | sort(production1, production1 + production1_num, [](const Production1& a, const Production1& b) 66 | { 67 | return a.child == b.child ? a.parent < b.parent : a.child < b.child; 68 | }); 69 | for (int i = 0; i < MAX_VT_NUM; i++) 70 | { 71 | vtIndex[i].begin = -1; 72 | vtIndex[i].num = 0; 73 | } 74 | for (int i = 0; i < production1_num; i++) 75 | { 76 | int t = production1[i].child; 77 | if (vtIndex[t].begin == -1) 78 | vtIndex[t].begin = i; 79 | vtIndex[t].num++; 80 | } 81 | for (int i = 0; i < string_length; i++) 82 | { 83 | int t = str[i]; 84 | int begin = vtIndex[t].begin; 85 | int end = begin + vtIndex[t].num; 86 | for (int j = begin; j < end; j++) 87 | { 88 | SubTree subTree; 89 | subTree.root = production1[j].parent; 90 | subTree.num = 1; 91 | subTreeTable[i][i][subTreeNumTable[i][i]++] = subTree; 92 | } 93 | } 94 | 95 | sort(production2, production2 + production2_num, [](const Production2& a, const Production2& b) 96 | { 97 | return a.child1 == b.child1 ? 98 | (a.child2 == b.child2 ? a.parent < b.parent : a.child2 < b.child2) 99 | : a.child1 < b.child1; 100 | }); 101 | for (int i = 0; i < vn_num; i++) 102 | { 103 | for (int j = 0; j < vn_num; j++) 104 | { 105 | vnIndex[i][j].begin = -1; 106 | vnIndex[i][j].num = 0; 107 | } 108 | } 109 | for (int i = 0; i < production2_num; i++) 110 | { 111 | int n1 = production2[i].child1; 112 | int n2 = production2[i].child2; 113 | if (vnIndex[n1][n2].begin == -1) 114 | vnIndex[n1][n2].begin = i; 115 | vnIndex[n1][n2].num++; 116 | } 117 | for (int len = 2; len <= string_length; len++) 118 | { 119 | for (int left = 0; left <= string_length - len; left++) 120 | { 121 | SubTree subTreeBuf[2][MAX_STRING_LENGTH]; 122 | //memset(subTreeBuf, 0, sizeof subTreeBuf); 123 | int curr = 0; 124 | int last = 1; 125 | int oldTreeNum = 0; 126 | for (int right = left + 1; right < left + len; right++) 127 | { 128 | //printf("[%d, %d] = [%d, %d] + [%d, %d]\n", left, left + len, left, right, right, left + len); 129 | for (int i1 = 0; i1 < subTreeNumTable[left][right - 1]; i1++) 130 | { 131 | SubTree subTreeChild1 = subTreeTable[left][right - 1][i1]; 132 | for (int i2 = 0; i2 < subTreeNumTable[right][left + len - 1]; i2++) 133 | { 134 | SubTree subTreeChild2 = subTreeTable[right][left + len - 1][i2]; 135 | int begin = vnIndex[subTreeChild1.root][subTreeChild2.root].begin; 136 | int end = begin + vnIndex[subTreeChild1.root][subTreeChild2.root].num; 137 | if (begin == end) 138 | { 139 | continue; 140 | } 141 | swap(last, curr); 142 | int newTreeNum = 0; 143 | int k = 0; 144 | for (int j = begin; j < end; j++) 145 | { 146 | SubTree subTreeParent; 147 | subTreeParent.root = production2[j].parent; 148 | subTreeParent.num = subTreeChild1.num * subTreeChild2.num; 149 | while (k < oldTreeNum && subTreeParent.root > subTreeBuf[last][k].root) 150 | subTreeBuf[curr][newTreeNum++] = subTreeBuf[last][k++]; 151 | if (k < oldTreeNum && subTreeParent.root == subTreeBuf[last][k].root) 152 | subTreeParent.num += subTreeBuf[last][k++].num; 153 | subTreeBuf[curr][newTreeNum++] = subTreeParent; 154 | } 155 | while (k < oldTreeNum) 156 | { 157 | subTreeBuf[curr][newTreeNum++] = subTreeBuf[last][k++]; 158 | } 159 | oldTreeNum = newTreeNum; 160 | } 161 | } 162 | } 163 | subTreeNumTable[left][left + len - 1] = oldTreeNum; 164 | if (subTreeNumTable[left][left + len - 1] > 0) 165 | { 166 | memcpy(subTreeTable[left][left + len - 1], subTreeBuf[curr], subTreeNumTable[left][left + len - 1] * sizeof(SubTree)); 167 | } 168 | } 169 | } 170 | unsigned treeNum = 0; 171 | if (subTreeNumTable[0][string_length - 1] > 0) 172 | { 173 | if (subTreeTable[0][string_length - 1][0].root == 0) 174 | { 175 | treeNum = subTreeTable[0][string_length - 1][0].num; 176 | } 177 | } 178 | printf("%u\n", treeNum); 179 | return 0; 180 | } -------------------------------------------------------------------------------- /final/summary.md: -------------------------------------------------------------------------------- 1 | # 实验报告 2 | 3 | > 学号:19373718 4 | > 5 | > 姓名:周勤 6 | 7 | ## 实现细节 8 | 9 | ### 作业初期遇到的问题 10 | 11 | 作业初期遇到的问题不算多,首先是希冀平台已经给出的串行代码逻辑比较复杂,而且没有注释,比较难读懂,刚开始读的时候会觉得**“这个代码的逻辑怎么这么乱”**。我第一遍读串行代码,读到一半就不读了,直接去Google上查了[CYK算法](https://en.wikipedia.org/wiki/CYK_algorithm)的具体原理以及大概的应用,明确了这是一个$O(n^3)$的区间dp之后,就直接开始写自己的串行代码了。 12 | 13 | 其次是并行方案的选择,这个我并没有花很久时间,基本上是从Pthreads、MPI、OpenMP三个里选一个。虽然我没有测试过,但是我先直接排除掉了MPI,因为MPI是多进程并行,速度上限是没有多线程高的。在Pthreads和OpenMP中,我最后选择了**OpenMP**,虽然Pthreads对于线程的控制粒度更小,但是这也意味着我必须要自己编写更多复杂的多线程相关代码,我最终并没有选择上限更高的Pthreads。 14 | 15 | ### 如何将任务进行分块 16 | 17 | 程序实现大致分为四个部分:**读入数据**、**数据预处理**、**区间dp**、**输出结果**。其中数据的读入和输出是不能并行的,数据预处理和区间dp都是可以进行并行计算的。而区间dp实际上占了绝大部分程序的运行时间,所以区间dp的并行化尤为重要,区间dp的串行伪代码如下: 18 | 19 | ```c++ 20 | // 枚举区间长度 21 | for(int len = 2;len <= slen;++len){ 22 | // 枚举区间左端点 23 | for(int left = 0;left <= slen - len;++left){ 24 | int right = left + len - 1; 25 | // 枚举区间中的点 26 | for(int mid = left;mid < right;++mid){ 27 | update_based_on_len(); // 更具体的细节不再给出 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | 这是很经典的一个区间dp,在CYK算法中最外层的`len`(区间长度)循环是有**循环依赖**的,必须按照从小到大的顺序进行最外层的循环。但是`left`和`mid`的循环都是没有循环依赖的,可以进行并行,我使用了如下的OpenMP编译指令进行并行计算: 34 | 35 | ````c++ 36 | #pragma omp parallel for schedule(dynamic) 37 | ```` 38 | 39 | 上面这条指令会在运行时动态地为每个线程分配计算任务,每个线程计算完当前任务后会继续计算新的任务,详情请查阅[OpenMP手册](https://www.openmp.org/wp-content/uploads/OpenMP3.1.pdf)(编译大作业使用的GCC版本为4.8.5,这个版本的GCC支持的是OpenMP 3.1)。对于数据预处理部分,我也采用了类似的编译指令进行并行计算。至此,我已经完成了大作业代码**最初始**的版本,初始的代码非常短,可以贴出来: 40 | 41 | ```c++ 42 | #include 43 | using namespace std; 44 | 45 | const int MAX_PRODUCTION2_NUM = 512; 46 | const int MAX_PRODUCTION1_NUM = 128; 47 | const int MAX_VN = 128; 48 | const int MAX_VT = 128; 49 | const int MAX_SLEN = 1024; 50 | 51 | int vn_num, p2_num, p1_num, slen; 52 | int p2[MAX_PRODUCTION2_NUM][3]; 53 | int p1[MAX_PRODUCTION1_NUM][2]; 54 | char str[MAX_SLEN]; 55 | int dp[MAX_SLEN][MAX_SLEN][MAX_VN]; 56 | 57 | int main() { 58 | freopen("input.txt", "r", stdin); 59 | scanf("%d\n", &vn_num); 60 | scanf("%d\n", &p2_num); 61 | for (int i = 0; i < p2_num; i++) 62 | scanf("<%d>::=<%d><%d>\n", &p2[i][0], &p2[i][1], &p2[i][2]); 63 | scanf("%d\n", &p1_num); 64 | for (int i = 0; i < p1_num; i++) scanf("<%d>::=%c\n", &p1[i][0], &p1[i][1]); 65 | scanf("%d\n", &slen); 66 | scanf("%s\n", str); 67 | 68 | #pragma omp parallel for schedule(dynamic) 69 | for (int i = 0; i < slen; ++i) { 70 | // 枚举所有Production1的规则 71 | for (int k = 0; k < p1_num; ++k) { 72 | if (str[i] == p1[k][1]) dp[i][i][p1[k][0]] = 1; 73 | } 74 | } 75 | 76 | for (int len = 2; len <= slen; ++len) { 77 | #pragma omp parallel for schedule(dynamic) 78 | for (int start = 0; start <= slen - len; ++start) { 79 | int end = start + len - 1; 80 | for (int mid = start; mid < end; ++mid) { 81 | // 枚举所有Production2的规则 82 | for (int i = 0; i < p2_num; ++i) { 83 | dp[start][end][p2[i][0]] += 84 | dp[start][mid][p2[i][1]] * dp[mid + 1][end][p2[i][2]]; 85 | } 86 | } 87 | } 88 | } 89 | 90 | printf("%u\n", dp[0][slen - 1][0]); 91 | return 0; 92 | } 93 | ``` 94 | 95 | ### 如何实现更大的加速比 96 | 97 | 上面这个最初始的版本有**很多不足**的地方,为了实现更高的加速比,我做了一些优化。本节提及的优化均是对于区间dp的优化,因为区间dp占了绝大部分的程序运行时间,其他的优化在这里就**不一一列出**了。 98 | 99 | #### 减少写内存的次数 100 | 101 | 在区间dp的最内层循环中,**每次**都要对三维数组进行写入,即对`dp[start][end][p2[i][0]]`进行写入,我们可以将相同`parent`的产生式的结果都先加出来,最后再写入`dp[start][end][p2[i][0]]`,这样可以加速程序执行,核心代码如下: 102 | 103 | ```c++ 104 | // 枚举每一个非终结符 105 | for (int i = 0; i < vn_num; ++i) { 106 | int sum = 0; 107 | // 将结果先加到sum中 108 | for (int j = 1; j < p22[i][0]; j += 2) { 109 | sum += dp[start][mid][p22[i][j]] * dp[mid + 1][end][p22[i][j + 1]]; 110 | } 111 | // 最后再写内存 112 | dp[start][end][i] += sum; 113 | } 114 | ``` 115 | 116 | #### 实现按需枚举 117 | 118 | 有些时候,枚举所有Production2并不是最优的,因为存在非终结符并不能推导出特定子串的情况。这种情况下,枚举所有Production2可能会计算很多次`0 × 0`,更关键的是增加了很多次三维数组的无效读写,这是非常致命的。可以通过**按需枚举**的方式来避免这种情况,希冀平台上的代码就是完全的按需枚举,大概思路是,记录下`s.substring(i,j)`可以由哪些非终结符推导出来,当计算区间$[k,j](kj)$时,就可以枚举记录下来的非终结符,使用特定的Production2直接得出结果,伪代码如下: 119 | 120 | ```c++ 121 | // 枚举可以推导出s.substring(start,mid)的非终结符 122 | for(auto vn1: vn_set[start][mid]){ 123 | // 枚举可以推导出s.substring(mid+1,end)的非终结符 124 | for(auto vn2: vn_set[mid+1][end]){ 125 | // 枚举两个child分别是vn1和vn2的Production2 126 | for(auto production: pset[vn1][vn2]){ 127 | // 使用production更新dp数组 128 | update_dp_with_production(); 129 | // 更新可以推导出s.substring(start,end)的非终结符集合 130 | update_vn_set(); 131 | } 132 | } 133 | } 134 | ``` 135 | 136 | #### 使用数组模拟STL 137 | 138 | 我在大作业的迭代过程中,使用数组**代替**了`vector`和`bitset`,进一步加快了大作业的执行速度。直接使用STL确实十分方便,但是使用STL的执行速度并没有直接使用数组快,我将数组的第一个元素作为`vector`长度,其余的元素作为`vector`中的数字,这样可以模拟`vector`。至于`bitset`,可以用位运算和数组进行模拟,这里就不贴出代码了,而且由于题目的数据范围限制,只需要**128**位的`bitset`,我使用了两个64位的无符号整数进行模拟。 139 | 140 | #### 对于缓存命中的优化 141 | 142 | 对于非终结符比较少的情况,可以**减小**dp数组第三维的大小,以此来提高缓存命中的概率。由于区间dp的最内层循环对dp数组的内存操作比较频繁(最耗时的操作**没有之一**),所以可以通过提高缓存命中率的相关优化加快程序的执行。我通过这一优化,使得我的大作业对于一些特定的用例,执行速度提高了**2**倍左右,事实上,如果继续进行缓存相关的优化,可以将执行速度加速得更快。 143 | 144 | ## 分析与实验 145 | 146 | ### 程序运行时间的测量 147 | 148 | 为了实际测量程序的运行时间,我使用了C++的**chrono**标准库,计算了从程序开始到结束的时间。这一部分的代码如下: 149 | 150 | ```c++ 151 | using namespace std; 152 | using namespace std::chrono; 153 | // 计时开始 154 | steady_clock::time_point t1 = steady_clock::now(); 155 | // 计时结束 156 | steady_clock::time_point t2 = steady_clock::now(); 157 | duration time_span = duration_cast>(t2 - t1); 158 | printf("Total Time: %fs\n", time_span.count()); 159 | ``` 160 | 161 | 需要注意的是,使用OpenMP时**不能**采用`clock()`函数来计时,因为`clock()`函数测量的是处理器的CPU时间,详情见[这里](https://blog.csdn.net/hqh45/article/details/50959296),使用`clock()`函数的结果除以线程数的测量方法也是错误的。 162 | 163 | ### 加速比与线程数的关系 164 | 165 | 下面,给出对于**第一个测试用例**,程序加速比与线程数的关系图:(希冀平台的串行代码运行时间为258.264s,图中的加速比是相对于希冀平台的串行代码而言的) 166 | 167 | ![图片1](../assets/summary_1.png) 168 | 169 | 最终的目标机是**16核**的,所以使用16线程可以获得最高的加速比。在**1至16线程**的范围内,程序的加速比大致随着线程数的增加而线性增加,因为在这个区间内,CPU会将每个线程放在不同的核上执行。而当线程的数量**高于16**时,程序的加速比开始缓慢下降,可以预见到,当创建的线程继续增大时,程序的加速比将会继续下降。另外,程序在单线程时的加速比为**66.830**,充分说明了重新写的串行代码的优越性。 170 | 171 | ## 结论 172 | 173 | ### 最终的实现方案 174 | 175 | 如前文所述,我最终提交的代码中包括了**按需枚举**、**缓存优化**、**数组模拟STL**、**减少写内存次数**等优化,代码总行数大概在**250行**左右。最重要的优化都围绕最内层循环展开,优化的核心思想是:**在算法层面**减少循环的总次数,**在指令层面**减少最内层循环中执行的指令的总开销,**在硬件层面**尽量使得CPU缓存命中,**在并行层面**能写成并行就不要写成串行。虽然对于比较小的计算任务,并行计算的通信开销可能比较大,但是这次大作业的计算量相对较大,计算开销远远大于通信开销。 176 | 177 | ### 仍可以改进的地方 178 | 179 | - 在不影响空间局部性的前提下,微调循环逻辑,让小循环永远在外层 180 | - 对于缓存作进一步的优化,增加缓存命中的概率,继续优化空间局部性 181 | - 动态适应应该采用的算法,从按需计算和枚举中动态选择,或者对于特定的数据采用超参数 182 | - 对于排序的部分采用并行,这一部分占用的时间极小,所以我的实现并没有使用并行 183 | - 使用Pthreads对程序进行重写,进一步减小无效计算开销 184 | 185 | 程序的优化是**没有极限**的,除此之外一定还有可以优化的地方,这里就不再发散了。 186 | -------------------------------------------------------------------------------- /lab1/lab1.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | **蒙特卡罗法**也称统计模拟法、统计试验法。是把概率现象作为研究对象的数值模拟方法。是按抽样调查法求取统计值来推定未知特性量的计算方法。蒙特卡罗是摩纳哥的著名赌城,该法为表明其随机抽样的本质而命名。 4 | 5 | 使用蒙特卡罗方法可以计算 PI 值,其具体方案为在一个正方形中作内切圆,向正方形中随机投掷 n 个足够多的点,根据面积关系计算 PI 值。 6 | 7 | 请你使用 **MPI** 实现蒙特卡罗方法计算 PI 值的并行化。 8 | 9 | 运行方式:`mpirun -np -8 <>` 10 | 11 | ## 输入形式 12 | 13 | 一行一个数字,表示一个进程模拟投掷的次数 14 | 15 | ## 输出形式 16 | 17 | 输出计算出的 PI 值 18 | 19 | ## 输入样例 20 | 21 | ``` 22 | 10000000 23 | ``` 24 | 25 | ## 输出样例 26 | 27 | ``` 28 | 3.141369 29 | ``` 30 | -------------------------------------------------------------------------------- /lab1/pi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "mpi.h" 5 | 6 | double get_rand() { return (double)rand() / (RAND_MAX / 2) - 1; } 7 | 8 | int main(int argc, char* argv[]) { 9 | int size, rank; 10 | int total, sum = 0, recv_sum = 0; 11 | 12 | MPI_Init(&argc, &argv); 13 | MPI_Comm_size(MPI_COMM_WORLD, &size); 14 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 15 | 16 | if (!rank) { 17 | scanf("%d", &total); 18 | } 19 | MPI_Bcast(&total, 1, MPI_INT, 0, MPI_COMM_WORLD); 20 | if (rank) { 21 | srand(rank); 22 | for (int i = 0; i < total; ++i) { 23 | double x = get_rand(); 24 | double y = get_rand(); 25 | if (x * x + y * y <= 1) sum++; 26 | } 27 | } 28 | MPI_Reduce(&sum, &recv_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); 29 | if (rank == 0) { 30 | printf("%f\n", (double)recv_sum / (total * (size - 1)) * 4); 31 | } 32 | 33 | MPI_Finalize(); 34 | } -------------------------------------------------------------------------------- /lab2/lab2.md: -------------------------------------------------------------------------------- 1 | ## 问题背景 2 | 3 | 一般来说,用户的密码都是经 MD5 哈希处理后存放在数据库里的。由于 MD5 是不可逆的,当你拿到一串被 MD5 处理过的字串,只能使用暴力破解的方式穷举所有的可能密码并生成 MD5 字串,然后和数据库里存储的 MD5 值进行对比。若得到的 MD5 值相同,那么该用户的密码就被破解出来了。 4 | 5 | 下表列出了密码的复杂程度及其对应的暴力破解所需的时间。(第一列是密码长度,第二列是全小写的密码,第三列是有大写字母的密码,第四列是又加上了数字和其它字符的密码) 6 | 7 | ![md5_1.png](../assets/md5_1.png) 8 | 9 | 如果你想知道自己的密码需要多少时间可以被破解,你可以访问[这个网站](http://howsecureismypassword.net/)。 10 | 11 | 上表中列出的时间是指串行暴力破解所需的时间,若利用并行程序破解密码,上表中的时间就可大大缩短了。 12 | 13 | ## 问题描述 14 | 15 | 设计一个暴力破解 MD5 密码的多进程程序。该程序从标准输入读入一长为 32 的字符串,该字符串为用户密码的 MD5 编码。破解成功后,程序在标准输出上打印该 MD5 值所对应的用户密码。已知,用户密码长度为 4 位,仅由小写字母和数字组成。请使用 MPI 来解决此问题。 16 | 17 | 注意阅读 `lib/md5driver.c` 中的 `void MDString(char*)` 函数,稍微修改该函数就可以生成并打印 MD5 编码。 18 | 19 | ## 输入形式 20 | 21 | 从控制台(标准输入)读入一个长为 32 的字符串,该字符串为用户密码的 MD5 编码 22 | 23 | ## 输出形式 24 | 25 | 向控制台(标准输出)打印用户密码 26 | 27 | ## 输入样例 28 | 29 | ``` 30 | 5d8f7ad81bcce4f3fd4ce5a1d0365d59 31 | ``` 32 | 33 | ## 输出样例 34 | 35 | ``` 36 | a123 37 | ``` 38 | -------------------------------------------------------------------------------- /lab2/lib/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************** 3 | ** md5.c ** 4 | ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** 5 | ** Created: 2/17/90 RLR ** 6 | ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** 7 | ********************************************************************** 8 | */ 9 | 10 | /* 11 | ********************************************************************** 12 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 13 | ** ** 14 | ** License to copy and use this software is granted provided that ** 15 | ** it is identified as the "RSA Data Security, Inc. MD5 Message ** 16 | ** Digest Algorithm" in all material mentioning or referencing this ** 17 | ** software or this function. ** 18 | ** ** 19 | ** License is also granted to make and use derivative works ** 20 | ** provided that such works are identified as "derived from the RSA ** 21 | ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** 22 | ** material mentioning or referencing the derived work. ** 23 | ** ** 24 | ** RSA Data Security, Inc. makes no representations concerning ** 25 | ** either the merchantability of this software or the suitability ** 26 | ** of this software for any particular purpose. It is provided "as ** 27 | ** is" without express or implied warranty of any kind. ** 28 | ** ** 29 | ** These notices must be retained in any copies of any part of this ** 30 | ** documentation and/or software. ** 31 | ********************************************************************** 32 | */ 33 | 34 | /* -- include the following line if the md5.h header file is separate -- */ 35 | #include "md5.h" 36 | 37 | /* forward declaration */ 38 | static void Transform (); 39 | 40 | static unsigned char PADDING[64] = { 41 | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 49 | }; 50 | 51 | /* F, G and H are basic MD5 functions: selection, majority, parity */ 52 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 53 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 54 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 55 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 56 | 57 | /* ROTATE_LEFT rotates x left n bits */ 58 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 59 | 60 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ 61 | /* Rotation is separate from addition to prevent recomputation */ 62 | #define FF(a, b, c, d, x, s, ac) \ 63 | {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ 64 | (a) = ROTATE_LEFT ((a), (s)); \ 65 | (a) += (b); \ 66 | } 67 | #define GG(a, b, c, d, x, s, ac) \ 68 | {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ 69 | (a) = ROTATE_LEFT ((a), (s)); \ 70 | (a) += (b); \ 71 | } 72 | #define HH(a, b, c, d, x, s, ac) \ 73 | {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ 74 | (a) = ROTATE_LEFT ((a), (s)); \ 75 | (a) += (b); \ 76 | } 77 | #define II(a, b, c, d, x, s, ac) \ 78 | {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ 79 | (a) = ROTATE_LEFT ((a), (s)); \ 80 | (a) += (b); \ 81 | } 82 | 83 | void MD5Init (mdContext) 84 | MD5_CTX *mdContext; 85 | { 86 | mdContext->i[0] = mdContext->i[1] = (UINT4)0; 87 | 88 | /* Load magic initialization constants. 89 | */ 90 | mdContext->buf[0] = (UINT4)0x67452301; 91 | mdContext->buf[1] = (UINT4)0xefcdab89; 92 | mdContext->buf[2] = (UINT4)0x98badcfe; 93 | mdContext->buf[3] = (UINT4)0x10325476; 94 | } 95 | 96 | void MD5Update (mdContext, inBuf, inLen) 97 | MD5_CTX *mdContext; 98 | unsigned char *inBuf; 99 | unsigned int inLen; 100 | { 101 | UINT4 in[16]; 102 | int mdi; 103 | unsigned int i, ii; 104 | 105 | /* compute number of bytes mod 64 */ 106 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 107 | 108 | /* update number of bits */ 109 | if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) 110 | mdContext->i[1]++; 111 | mdContext->i[0] += ((UINT4)inLen << 3); 112 | mdContext->i[1] += ((UINT4)inLen >> 29); 113 | 114 | while (inLen--) { 115 | /* add new character to buffer, increment mdi */ 116 | mdContext->in[mdi++] = *inBuf++; 117 | 118 | /* transform if necessary */ 119 | if (mdi == 0x40) { 120 | for (i = 0, ii = 0; i < 16; i++, ii += 4) 121 | in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | 122 | (((UINT4)mdContext->in[ii+2]) << 16) | 123 | (((UINT4)mdContext->in[ii+1]) << 8) | 124 | ((UINT4)mdContext->in[ii]); 125 | Transform (mdContext->buf, in); 126 | mdi = 0; 127 | } 128 | } 129 | } 130 | 131 | void MD5Final (mdContext) 132 | MD5_CTX *mdContext; 133 | { 134 | UINT4 in[16]; 135 | int mdi; 136 | unsigned int i, ii; 137 | unsigned int padLen; 138 | 139 | /* save number of bits */ 140 | in[14] = mdContext->i[0]; 141 | in[15] = mdContext->i[1]; 142 | 143 | /* compute number of bytes mod 64 */ 144 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 145 | 146 | /* pad out to 56 mod 64 */ 147 | padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); 148 | MD5Update (mdContext, PADDING, padLen); 149 | 150 | /* append length in bits and transform */ 151 | for (i = 0, ii = 0; i < 14; i++, ii += 4) 152 | in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | 153 | (((UINT4)mdContext->in[ii+2]) << 16) | 154 | (((UINT4)mdContext->in[ii+1]) << 8) | 155 | ((UINT4)mdContext->in[ii]); 156 | Transform (mdContext->buf, in); 157 | 158 | /* store buffer in digest */ 159 | for (i = 0, ii = 0; i < 4; i++, ii += 4) { 160 | mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); 161 | mdContext->digest[ii+1] = 162 | (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); 163 | mdContext->digest[ii+2] = 164 | (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); 165 | mdContext->digest[ii+3] = 166 | (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); 167 | } 168 | } 169 | 170 | /* Basic MD5 step. Transform buf based on in. 171 | */ 172 | static void Transform (buf, in) 173 | UINT4 *buf; 174 | UINT4 *in; 175 | { 176 | UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; 177 | 178 | /* Round 1 */ 179 | #define S11 7 180 | #define S12 12 181 | #define S13 17 182 | #define S14 22 183 | FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */ 184 | FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */ 185 | FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */ 186 | FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */ 187 | FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */ 188 | FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */ 189 | FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */ 190 | FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */ 191 | FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */ 192 | FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */ 193 | FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */ 194 | FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */ 195 | FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */ 196 | FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */ 197 | FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */ 198 | FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */ 199 | 200 | /* Round 2 */ 201 | #define S21 5 202 | #define S22 9 203 | #define S23 14 204 | #define S24 20 205 | GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */ 206 | GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */ 207 | GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */ 208 | GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */ 209 | GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */ 210 | GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */ 211 | GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */ 212 | GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */ 213 | GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */ 214 | GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */ 215 | GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */ 216 | GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */ 217 | GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */ 218 | GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */ 219 | GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */ 220 | GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */ 221 | 222 | /* Round 3 */ 223 | #define S31 4 224 | #define S32 11 225 | #define S33 16 226 | #define S34 23 227 | HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */ 228 | HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */ 229 | HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */ 230 | HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */ 231 | HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */ 232 | HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */ 233 | HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */ 234 | HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */ 235 | HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */ 236 | HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */ 237 | HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */ 238 | HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */ 239 | HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */ 240 | HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */ 241 | HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */ 242 | HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */ 243 | 244 | /* Round 4 */ 245 | #define S41 6 246 | #define S42 10 247 | #define S43 15 248 | #define S44 21 249 | II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */ 250 | II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */ 251 | II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */ 252 | II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */ 253 | II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */ 254 | II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */ 255 | II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */ 256 | II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */ 257 | II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */ 258 | II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */ 259 | II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */ 260 | II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */ 261 | II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */ 262 | II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */ 263 | II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */ 264 | II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */ 265 | 266 | buf[0] += a; 267 | buf[1] += b; 268 | buf[2] += c; 269 | buf[3] += d; 270 | } 271 | 272 | /* 273 | ********************************************************************** 274 | ** End of md5.c ** 275 | ******************************* (cut) ******************************** 276 | */ 277 | -------------------------------------------------------------------------------- /lab2/lib/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************** 3 | ** md5.h -- Header file for implementation of MD5 ** 4 | ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** 5 | ** Created: 2/17/90 RLR ** 6 | ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** 7 | ** Revised (for MD5): RLR 4/27/91 ** 8 | ** -- G modified to have y&~z instead of y&z ** 9 | ** -- FF, GG, HH modified to add in last register done ** 10 | ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** 11 | ** -- distinct additive constant for each step ** 12 | ** -- round 4 added, working mod 7 ** 13 | ********************************************************************** 14 | */ 15 | 16 | /* 17 | ********************************************************************** 18 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 19 | ** ** 20 | ** License to copy and use this software is granted provided that ** 21 | ** it is identified as the "RSA Data Security, Inc. MD5 Message ** 22 | ** Digest Algorithm" in all material mentioning or referencing this ** 23 | ** software or this function. ** 24 | ** ** 25 | ** License is also granted to make and use derivative works ** 26 | ** provided that such works are identified as "derived from the RSA ** 27 | ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** 28 | ** material mentioning or referencing the derived work. ** 29 | ** ** 30 | ** RSA Data Security, Inc. makes no representations concerning ** 31 | ** either the merchantability of this software or the suitability ** 32 | ** of this software for any particular purpose. It is provided "as ** 33 | ** is" without express or implied warranty of any kind. ** 34 | ** ** 35 | ** These notices must be retained in any copies of any part of this ** 36 | ** documentation and/or software. ** 37 | ********************************************************************** 38 | */ 39 | 40 | /* typedef a 32 bit type */ 41 | typedef unsigned long int UINT4; 42 | 43 | /* Data structure for MD5 (Message Digest) computation */ 44 | typedef struct { 45 | UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ 46 | UINT4 buf[4]; /* scratch buffer */ 47 | unsigned char in[64]; /* input buffer */ 48 | unsigned char digest[16]; /* actual digest after MD5Final call */ 49 | } MD5_CTX; 50 | 51 | void MD5Init (); 52 | void MD5Update (); 53 | void MD5Final (); 54 | 55 | /* 56 | ********************************************************************** 57 | ** End of md5.h ** 58 | ******************************* (cut) ******************************** 59 | */ 60 | 61 | -------------------------------------------------------------------------------- /lab2/lib/md5driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | ********************************************************************** 3 | ** md5driver.c -- sample routines to test ** 4 | ** RSA Data Security, Inc. MD5 message digest algorithm. ** 5 | ** Created: 2/16/90 RLR ** 6 | ** Updated: 1/91 SRD ** 7 | ********************************************************************** 8 | */ 9 | 10 | /* 11 | ********************************************************************** 12 | ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** 13 | ** ** 14 | ** RSA Data Security, Inc. makes no representations concerning ** 15 | ** either the merchantability of this software or the suitability ** 16 | ** of this software for any particular purpose. It is provided "as ** 17 | ** is" without express or implied warranty of any kind. ** 18 | ** ** 19 | ** These notices must be retained in any copies of any part of this ** 20 | ** documentation and/or software. ** 21 | ********************************************************************** 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | /* -- include the following file if the file md5.h is separate -- */ 29 | #include "md5.h" 30 | 31 | /* Prints message digest buffer in mdContext as 32 hexadecimal digits. 32 | Order is from low-order byte to high-order byte of digest. 33 | Each byte is printed with high-order hexadecimal digit first. 34 | */ 35 | static void MDPrint (mdContext) 36 | MD5_CTX *mdContext; 37 | { 38 | int i; 39 | 40 | for (i = 0; i < 16; i++) 41 | printf ("%02x", mdContext->digest[i]); 42 | } 43 | 44 | /* size of test block */ 45 | #define TEST_BLOCK_SIZE 1000 46 | 47 | /* number of blocks to process */ 48 | #define TEST_BLOCKS 10000 49 | 50 | /* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */ 51 | static long TEST_BYTES = (long)TEST_BLOCK_SIZE * (long)TEST_BLOCKS; 52 | 53 | /* A time trial routine, to measure the speed of MD5. 54 | Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE 55 | characters. 56 | */ 57 | static void MDTimeTrial () 58 | { 59 | MD5_CTX mdContext; 60 | time_t endTime, startTime; 61 | unsigned char data[TEST_BLOCK_SIZE]; 62 | unsigned int i; 63 | 64 | /* initialize test data */ 65 | for (i = 0; i < TEST_BLOCK_SIZE; i++) 66 | data[i] = (unsigned char)(i & 0xFF); 67 | 68 | /* start timer */ 69 | printf ("MD5 time trial. Processing %ld characters...\n", TEST_BYTES); 70 | time (&startTime); 71 | 72 | /* digest data in TEST_BLOCK_SIZE byte blocks */ 73 | MD5Init (&mdContext); 74 | for (i = TEST_BLOCKS; i > 0; i--) 75 | MD5Update (&mdContext, data, TEST_BLOCK_SIZE); 76 | MD5Final (&mdContext); 77 | 78 | /* stop timer, get time difference */ 79 | time (&endTime); 80 | MDPrint (&mdContext); 81 | printf (" is digest of test input.\n"); 82 | printf 83 | ("Seconds to process test input: %ld\n", (long)(endTime-startTime)); 84 | printf 85 | ("Characters processed per second: %ld\n", 86 | TEST_BYTES/(endTime-startTime)); 87 | } 88 | 89 | /* Computes the message digest for string inString. 90 | Prints out message digest, a space, the string (in quotes) and a 91 | carriage return. 92 | */ 93 | static void MDString (inString) 94 | char *inString; 95 | { 96 | MD5_CTX mdContext; 97 | unsigned int len = strlen (inString); 98 | 99 | MD5Init (&mdContext); 100 | MD5Update (&mdContext, inString, len); 101 | MD5Final (&mdContext); 102 | MDPrint (&mdContext); 103 | printf (" \"%s\"\n\n", inString); 104 | } 105 | 106 | /* Computes the message digest for a specified file. 107 | Prints out message digest, a space, the file name, and a carriage 108 | return. 109 | */ 110 | static void MDFile (filename) 111 | char *filename; 112 | { 113 | FILE *inFile = fopen (filename, "rb"); 114 | MD5_CTX mdContext; 115 | int bytes; 116 | unsigned char data[1024]; 117 | 118 | if (inFile == NULL) { 119 | printf ("%s can't be opened.\n", filename); 120 | return; 121 | } 122 | 123 | MD5Init (&mdContext); 124 | while ((bytes = fread (data, 1, 1024, inFile)) != 0) 125 | MD5Update (&mdContext, data, bytes); 126 | MD5Final (&mdContext); 127 | MDPrint (&mdContext); 128 | printf (" %s\n", filename); 129 | fclose (inFile); 130 | } 131 | 132 | /* Writes the message digest of the data from stdin onto stdout, 133 | followed by a carriage return. 134 | */ 135 | static void MDFilter () 136 | { 137 | MD5_CTX mdContext; 138 | int bytes; 139 | unsigned char data[16]; 140 | 141 | MD5Init (&mdContext); 142 | while ((bytes = fread (data, 1, 16, stdin)) != 0) 143 | MD5Update (&mdContext, data, bytes); 144 | MD5Final (&mdContext); 145 | MDPrint (&mdContext); 146 | printf ("\n"); 147 | } 148 | 149 | /* Runs a standard suite of test data. 150 | */ 151 | static void MDTestSuite () 152 | { 153 | printf ("MD5 test suite results:\n\n"); 154 | MDString (""); 155 | MDString ("a"); 156 | MDString ("abc"); 157 | MDString ("message digest"); 158 | MDString ("abcdefghijklmnopqrstuvwxyz"); 159 | MDString 160 | ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 161 | MDString 162 | ("1234567890123456789012345678901234567890\ 163 | 1234567890123456789012345678901234567890"); 164 | /* Contents of file foo are "abc" */ 165 | MDFile ("foo"); 166 | } 167 | 168 | void main (argc, argv) 169 | int argc; 170 | char *argv[]; 171 | { 172 | int i; 173 | 174 | /* For each command line argument in turn: 175 | ** filename -- prints message digest and name of file 176 | ** -sstring -- prints message digest and contents of string 177 | ** -t -- prints time trial statistics for 1M characters 178 | ** -x -- execute a standard suite of test data 179 | ** (no args) -- writes messages digest of stdin onto stdout 180 | */ 181 | if (argc == 1) 182 | MDFilter (); 183 | else 184 | for (i = 1; i < argc; i++) 185 | if (argv[i][0] == '-' && argv[i][1] == 's') 186 | MDString (argv[i] + 2); 187 | else if (strcmp (argv[i], "-t") == 0) 188 | MDTimeTrial (); 189 | else if (strcmp (argv[i], "-x") == 0) 190 | MDTestSuite (); 191 | else MDFile (argv[i]); 192 | } 193 | 194 | /* 195 | ********************************************************************** 196 | ** End of md5driver.c ** 197 | ******************************* (cut) ******************************** 198 | */ 199 | -------------------------------------------------------------------------------- /lab2/md5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mpi.h" 4 | 5 | /* typedef a 32 bit type */ 6 | typedef unsigned long int UINT4; 7 | 8 | /* Data structure for MD5 (Message Digest) computation */ 9 | typedef struct { 10 | UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ 11 | UINT4 buf[4]; /* scratch buffer */ 12 | unsigned char in[64]; /* input buffer */ 13 | unsigned char digest[16]; /* actual digest after MD5Final call */ 14 | } MD5_CTX; 15 | 16 | void MD5Init (); 17 | void MD5Update (); 18 | void MD5Final (); 19 | 20 | /* forward declaration */ 21 | static void Transform (); 22 | 23 | static unsigned char PADDING[64] = { 24 | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 32 | }; 33 | 34 | /* F, G and H are basic MD5 functions: selection, majority, parity */ 35 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 36 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 37 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 38 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 39 | 40 | /* ROTATE_LEFT rotates x left n bits */ 41 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 42 | 43 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ 44 | /* Rotation is separate from addition to prevent recomputation */ 45 | #define FF(a, b, c, d, x, s, ac) \ 46 | {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ 47 | (a) = ROTATE_LEFT ((a), (s)); \ 48 | (a) += (b); \ 49 | } 50 | #define GG(a, b, c, d, x, s, ac) \ 51 | {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ 52 | (a) = ROTATE_LEFT ((a), (s)); \ 53 | (a) += (b); \ 54 | } 55 | #define HH(a, b, c, d, x, s, ac) \ 56 | {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ 57 | (a) = ROTATE_LEFT ((a), (s)); \ 58 | (a) += (b); \ 59 | } 60 | #define II(a, b, c, d, x, s, ac) \ 61 | {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ 62 | (a) = ROTATE_LEFT ((a), (s)); \ 63 | (a) += (b); \ 64 | } 65 | 66 | void MD5Init (mdContext) 67 | MD5_CTX *mdContext; 68 | { 69 | mdContext->i[0] = mdContext->i[1] = (UINT4)0; 70 | 71 | /* Load magic initialization constants. 72 | */ 73 | mdContext->buf[0] = (UINT4)0x67452301; 74 | mdContext->buf[1] = (UINT4)0xefcdab89; 75 | mdContext->buf[2] = (UINT4)0x98badcfe; 76 | mdContext->buf[3] = (UINT4)0x10325476; 77 | } 78 | 79 | void MD5Update (mdContext, inBuf, inLen) 80 | MD5_CTX *mdContext; 81 | unsigned char *inBuf; 82 | unsigned int inLen; 83 | { 84 | UINT4 in[16]; 85 | int mdi; 86 | unsigned int i, ii; 87 | 88 | /* compute number of bytes mod 64 */ 89 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 90 | 91 | /* update number of bits */ 92 | if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) 93 | mdContext->i[1]++; 94 | mdContext->i[0] += ((UINT4)inLen << 3); 95 | mdContext->i[1] += ((UINT4)inLen >> 29); 96 | 97 | while (inLen--) { 98 | /* add new character to buffer, increment mdi */ 99 | mdContext->in[mdi++] = *inBuf++; 100 | 101 | /* transform if necessary */ 102 | if (mdi == 0x40) { 103 | for (i = 0, ii = 0; i < 16; i++, ii += 4) 104 | in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | 105 | (((UINT4)mdContext->in[ii+2]) << 16) | 106 | (((UINT4)mdContext->in[ii+1]) << 8) | 107 | ((UINT4)mdContext->in[ii]); 108 | Transform (mdContext->buf, in); 109 | mdi = 0; 110 | } 111 | } 112 | } 113 | 114 | void MD5Final (mdContext) 115 | MD5_CTX *mdContext; 116 | { 117 | UINT4 in[16]; 118 | int mdi; 119 | unsigned int i, ii; 120 | unsigned int padLen; 121 | 122 | /* save number of bits */ 123 | in[14] = mdContext->i[0]; 124 | in[15] = mdContext->i[1]; 125 | 126 | /* compute number of bytes mod 64 */ 127 | mdi = (int)((mdContext->i[0] >> 3) & 0x3F); 128 | 129 | /* pad out to 56 mod 64 */ 130 | padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); 131 | MD5Update (mdContext, PADDING, padLen); 132 | 133 | /* append length in bits and transform */ 134 | for (i = 0, ii = 0; i < 14; i++, ii += 4) 135 | in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | 136 | (((UINT4)mdContext->in[ii+2]) << 16) | 137 | (((UINT4)mdContext->in[ii+1]) << 8) | 138 | ((UINT4)mdContext->in[ii]); 139 | Transform (mdContext->buf, in); 140 | 141 | /* store buffer in digest */ 142 | for (i = 0, ii = 0; i < 4; i++, ii += 4) { 143 | mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); 144 | mdContext->digest[ii+1] = 145 | (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); 146 | mdContext->digest[ii+2] = 147 | (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); 148 | mdContext->digest[ii+3] = 149 | (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); 150 | } 151 | } 152 | 153 | /* Basic MD5 step. Transform buf based on in. 154 | */ 155 | static void Transform (buf, in) 156 | UINT4 *buf; 157 | UINT4 *in; 158 | { 159 | UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; 160 | 161 | /* Round 1 */ 162 | #define S11 7 163 | #define S12 12 164 | #define S13 17 165 | #define S14 22 166 | FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */ 167 | FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */ 168 | FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */ 169 | FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */ 170 | FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */ 171 | FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */ 172 | FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */ 173 | FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */ 174 | FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */ 175 | FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */ 176 | FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */ 177 | FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */ 178 | FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */ 179 | FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */ 180 | FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */ 181 | FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */ 182 | 183 | /* Round 2 */ 184 | #define S21 5 185 | #define S22 9 186 | #define S23 14 187 | #define S24 20 188 | GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */ 189 | GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */ 190 | GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */ 191 | GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */ 192 | GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */ 193 | GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */ 194 | GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */ 195 | GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */ 196 | GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */ 197 | GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */ 198 | GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */ 199 | GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */ 200 | GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */ 201 | GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */ 202 | GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */ 203 | GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */ 204 | 205 | /* Round 3 */ 206 | #define S31 4 207 | #define S32 11 208 | #define S33 16 209 | #define S34 23 210 | HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */ 211 | HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */ 212 | HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */ 213 | HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */ 214 | HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */ 215 | HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */ 216 | HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */ 217 | HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */ 218 | HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */ 219 | HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */ 220 | HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */ 221 | HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */ 222 | HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */ 223 | HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */ 224 | HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */ 225 | HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */ 226 | 227 | /* Round 4 */ 228 | #define S41 6 229 | #define S42 10 230 | #define S43 15 231 | #define S44 21 232 | II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */ 233 | II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */ 234 | II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */ 235 | II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */ 236 | II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */ 237 | II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */ 238 | II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */ 239 | II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */ 240 | II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */ 241 | II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */ 242 | II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */ 243 | II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */ 244 | II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */ 245 | II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */ 246 | II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */ 247 | II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */ 248 | 249 | buf[0] += a; 250 | buf[1] += b; 251 | buf[2] += c; 252 | buf[3] += d; 253 | } 254 | 255 | /* Computes the message digest for string inString. 256 | Prints out message digest, a space, the string (in quotes) and a 257 | carriage return. 258 | */ 259 | static void MDString (inString,outString) 260 | char *inString; 261 | char *outString; 262 | { 263 | MD5_CTX mdContext; 264 | unsigned int len = strlen (inString); 265 | 266 | MD5Init (&mdContext); 267 | MD5Update (&mdContext, inString, len); 268 | MD5Final (&mdContext); 269 | 270 | for (int i = 0; i < 16; i++) 271 | sprintf (outString+2*i,"%02x", mdContext.digest[i]); 272 | outString[32]='\0'; 273 | } 274 | 275 | char input[50],output[50],test[50],set[36]; 276 | 277 | void main (argc, argv) 278 | int argc; 279 | char *argv[]; 280 | { 281 | 282 | int size, rank,i,x,y,z,start_pos,end_pos; 283 | 284 | MPI_Init(&argc, &argv); 285 | MPI_Comm_size(MPI_COMM_WORLD, &size); 286 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 287 | 288 | if (!rank) { 289 | scanf("%s", input); 290 | } 291 | MPI_Bcast(input, 49, MPI_CHAR, 0, MPI_COMM_WORLD); 292 | 293 | // init character set 294 | for(i=0;i<10;++i) set[i]='0'+i; 295 | for(i=0;i<26;++i) set[i+10]='a'+i; 296 | start_pos=36/size*rank; 297 | end_pos=36/size+start_pos; 298 | // traverse 299 | for(i=start_pos;i 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | int id; 8 | } thread_data_t; 9 | 10 | int n, num_of_thread, num, method; 11 | double a, b, sum; 12 | 13 | sem_t sum_sem; 14 | pthread_mutex_t lock; 15 | int flag; 16 | 17 | double f(double x) { return x * x + x; } 18 | 19 | void* calculate(void* arg) { 20 | // trapezoidal integral 21 | thread_data_t* data = (thread_data_t*)arg; 22 | double h = (b - a) / n; 23 | double start = a + data->id * h * num; 24 | double end = start + h * num; 25 | double tmp = (f(start) + f(end)) / 2; 26 | for (int i = 1; i < num; i++) { 27 | tmp += f(start + i * h); 28 | } 29 | tmp *= h; 30 | if (method == 3) { 31 | sem_wait(&sum_sem); 32 | sum += tmp; 33 | sem_post(&sum_sem); 34 | } else if (method == 2) { 35 | pthread_mutex_lock(&lock); 36 | sum += tmp; 37 | pthread_mutex_unlock(&lock); 38 | } else { 39 | while (data->id != flag) 40 | ; 41 | sum += tmp; 42 | flag = (flag + 1) % num_of_thread; 43 | } 44 | pthread_exit(NULL); 45 | } 46 | 47 | int main(int argc, char* argv[]) { 48 | // read a,b,n from stdin 49 | scanf("%lf%lf%d", &a, &b, &n); 50 | 51 | // read num_of_thread,method from command line 52 | num_of_thread = atoi(argv[1]); 53 | method = atoi(argv[2]); 54 | 55 | // init 56 | if (method == 3) 57 | sem_init(&sum_sem, 0, 1); 58 | else if (method == 2) 59 | pthread_mutex_init(&lock, NULL); 60 | 61 | // create threads 62 | num = n / num_of_thread; 63 | pthread_t* threads = (pthread_t*)malloc(num_of_thread * sizeof(pthread_t)); 64 | thread_data_t* data = 65 | (thread_data_t*)malloc(num_of_thread * sizeof(thread_data_t)); 66 | for (int i = 0; i < num_of_thread; i++) { 67 | data[i].id = i; 68 | pthread_create(&threads[i], NULL, calculate, (void*)&data[i]); 69 | } 70 | 71 | // join threads 72 | for (int i = 0; i < num_of_thread; i++) { 73 | pthread_join(threads[i], NULL); 74 | } 75 | 76 | // print sum 77 | printf("%f\n", sum); 78 | 79 | // release memory 80 | free(threads); 81 | free(data); 82 | 83 | // return 84 | return 0; 85 | } -------------------------------------------------------------------------------- /lab3/lab3.md: -------------------------------------------------------------------------------- 1 | ## 问题描述 2 | 3 | ![trap_1.png](../assets/trap_1.png) 4 | 5 | 编写一个 Pthreads 程序使用梯形积分求出函数 𝑓(𝑥)=𝑥^2+𝑥 在区间[𝑎,𝑏]的定积分。使用一个共享变量来表示所有计算线程的总和。在程序中分别使用忙等待,互斥量和信号量三种方式来保证临界区的互斥。 6 | 7 | 运行方式:`./pth_trap <> <>` 8 | 9 | 当 method 值为 1 时使用忙等待,method 值为 2 时使用互斥量,method 值为 3 时使用信号量。 10 | 11 | ## 输入形式 12 | 13 | 一行三个数字,分别表示 a, b, n 的值 14 | 15 | ## 输出形式 16 | 17 | 一行一个数字,表示函数 𝑓(𝑥)=𝑥^2+𝑥 在区间[𝑎,𝑏]的定积分 18 | 19 | ## 输入样例 20 | 21 | ``` 22 | 0 100 400 23 | ``` 24 | 25 | ## 输出样例 26 | 27 | ``` 28 | 338334.375000 29 | ``` 30 | -------------------------------------------------------------------------------- /lab4/histogram.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | // get b,thread_count,left,right from command line 7 | int b = atoi(argv[1]); 8 | int thread_count = atoi(argv[2]); 9 | double left = atof(argv[3]); 10 | double right = atof(argv[4]); 11 | // get n,a1,a2...an from stdin 12 | int n; 13 | scanf("%d", &n); 14 | double *a = (double *)malloc(n * sizeof(double)); 15 | for (int i = 0; i < n; i++) { 16 | scanf("%lf", &a[i]); 17 | } 18 | // allocate histogram 19 | int *histogram = (int *)malloc(sizeof(int) * b); 20 | // initialize histogram 21 | for (int i = 0; i < b; i++) { 22 | histogram[i] = 0; 23 | } 24 | // get range 25 | double range = right - left; 26 | // get step 27 | double step = range / b; 28 | // set number of threads 29 | omp_set_num_threads(thread_count); 30 | // parallel region 31 | #pragma omp parallel 32 | { 33 | // get thread id 34 | int tid = omp_get_thread_num(); 35 | // get number of elements to process 36 | int n_elements = n / thread_count; 37 | // get start and end index 38 | int start_index = tid * n_elements; 39 | int end_index = (tid + 1) * n_elements; 40 | // process elements 41 | for (int i = start_index; i < end_index; i++) { 42 | // get element 43 | double element = a[i]; 44 | // get index 45 | int index = (int)((element - left) / step); 46 | // check if index is in range 47 | if (index >= 0 && index < b) { 48 | // increment histogram 49 | #pragma omp atomic 50 | histogram[index]++; 51 | } 52 | } 53 | } 54 | // print histogram 55 | for (int i = 0; i < b; i++) { 56 | printf("From %.3f to %.3f: %d\n", left + i * step, left + i * step + step, 57 | histogram[i]); 58 | } 59 | return 0; 60 | } -------------------------------------------------------------------------------- /lab4/lab4.md: -------------------------------------------------------------------------------- 1 | ## 问题描述 2 | 3 | 此次 OpenMP 作业是上课提到过的例子,比较简单,《并行程序设计导论》第 48 页也有提及。请使用 OpenMP 实现第二章所讲的并行直方图,详情如下。 4 | 5 | 编译方式:`gcc -g -Wall -fopenmp -o omp_histogram omp_histogram.c` 6 | 7 | 运行方式:`./omp_histogram <<桶数 b>> <<线程数>> <<区间左端点>> <<区间右端点>>` 8 | 9 | ## 输入形式 10 | 11 | 数的个数 n 和数 𝑎1, 𝑎2, 𝑎3,…, 𝑎𝑛(所有数保证在区间范围内) 12 | 13 | ## 输出形式 14 | 15 | 桶数 b 行,每行输出该桶表示的区间范围和在该范围的数字个数 16 | 17 | 区间左闭右开,例如,1.00 在区间 From 1.000 to 2.000 中 18 | 19 | ## 输入样例 20 | 21 | ``` 22 | ./omp_histogram 8 4 -4.0 4.0 23 | 16 -3.5 -3.3 -3.2 -2.1 -1.2 -0.3 0.5 0.1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 24 | ``` 25 | 26 | ## 输出样例 27 | 28 | ``` 29 | From -4.000 to -3.000: 3 30 | From -3.000 to -2.000: 1 31 | From -2.000 to -1.000: 1 32 | From -1.000 to -0.000: 1 33 | From 0.000 to 1.000: 2 34 | From 1.000 to 2.000: 8 35 | From 2.000 to 3.000: 0 36 | From 3.000 to 4.000: 0 37 | ``` 38 | -------------------------------------------------------------------------------- /pdf/Chapter_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/pdf/Chapter_1.pdf -------------------------------------------------------------------------------- /pdf/Chapter_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/pdf/Chapter_2.pdf -------------------------------------------------------------------------------- /pdf/Chapter_3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/pdf/Chapter_3.pdf -------------------------------------------------------------------------------- /pdf/Chapter_4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/pdf/Chapter_4.pdf -------------------------------------------------------------------------------- /pdf/Chapter_5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/pdf/Chapter_5.pdf -------------------------------------------------------------------------------- /pdf/Chapter_6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/pdf/Chapter_6.pdf -------------------------------------------------------------------------------- /pdf/Chapter_7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Matrix53/parallel-programming/3d979905033626073a16a6792953a73ba246fb5f/pdf/Chapter_7.pdf --------------------------------------------------------------------------------