1 00:00:00 --> 00:00:00 2 00:00:00 --> 00:00:02 The following content is provided under a 3 00:00:02 --> 00:00:03 Creative Commons license. 4 00:00:03 --> 00:00:06 Your support will help MIT OpenCourseWare continue to 5 00:00:06 --> 00:00:10 offer high quality educational resources for free. 6 00:00:10 --> 00:00:13 To make a donation, or view additional materials from 7 00:00:13 --> 00:00:17 hundreds of MIT courses, visit MIT OpenCourseWare 8 00:00:17 --> 00:00:22 at ocw.mit.edu. 9 00:00:22 --> 00:00:27 PROFESSOR: At the end of the lecture on Tuesday, a number of 10 00:00:27 --> 00:00:30 people asked me questions, asked Professor Grimson 11 00:00:30 --> 00:00:35 questions, which made it clear that I had been less than clear 12 00:00:35 --> 00:00:40 on at least a few things, so I want to come back and revisit a 13 00:00:40 --> 00:00:43 couple of the things we talked about at the end 14 00:00:43 --> 00:00:45 of the lecture. 15 00:00:45 --> 00:00:58 You'll remember that I had drawn this decision tree, in 16 00:00:58 --> 00:01:00 part because it's an important concept I want you to 17 00:01:00 --> 00:01:05 understand, the concept of decision trees, and also to 18 00:01:05 --> 00:01:09 illustrate, I hope, visually, some things related to 19 00:01:09 --> 00:01:11 dynamic programming. 20 00:01:11 --> 00:01:17 So we had in that decision tree, is we had the weight 21 00:01:17 --> 00:01:24 vector, and I just given a very simple one [5,3,2], and we had 22 00:01:24 --> 00:01:32 a very simple value vector, [9,7,8]. 23 00:01:32 --> 00:01:44 And then the way we drew the tree, was we started at the 24 00:01:44 --> 00:01:53 top, and said all right, we're going to first look at item 25 00:01:53 --> 00:01:57 number 2, which was the third item in our list of items, of 26 00:01:57 --> 00:02:04 course, and say that we had five pounds left of weight that 27 00:02:04 --> 00:02:11 our knapsack that could hold, and currently had a value of 0. 28 00:02:11 --> 00:02:18 And then we made a decision, to not put that last item in the 29 00:02:18 --> 00:02:24 backpack, and said if we made that decision, the next item we 30 00:02:24 --> 00:02:29 had to consider was item 1, we still had five pounds 31 00:02:29 --> 00:02:35 available, and we still had a weight 0 available. 32 00:02:35 --> 00:02:40 Now I, said the next item to consider is item 1, but really 33 00:02:40 --> 00:02:45 what I meant is, 1 and all of the items proceeding 34 00:02:45 --> 00:02:47 it in the list. 35 00:02:47 --> 00:02:52 This is my shorthand for saying the list up to and including 36 00:02:52 --> 00:02:58 items sub 1, kind of a normal way to think about it. 37 00:02:58 --> 00:03:02 And then we finish building the tree, left first step first, 38 00:03:02 --> 00:03:09 looking at all the no branches, 0,5,0 and then we were 39 00:03:09 --> 00:03:15 done, that was one branch. 40 00:03:15 --> 00:03:21 We then backed up, and said let's look at a yes, we'll 41 00:03:21 --> 00:03:25 include item number 1. 42 00:03:25 --> 00:03:33 Well, what happens here, if we've included that, it uses 43 00:03:33 --> 00:03:37 up all the available weight, and gave us the value of 9. 44 00:03:37 --> 00:03:41 STUDENT: [UNINTELLIGIBLE] 45 00:03:41 --> 00:03:44 PROFESSOR: Pardon? 46 00:03:44 --> 00:03:49 STUDENT: -- want to be off the bottom branch. 47 00:03:49 --> 00:03:52 PROFESSOR: Yup, Off by 1. 48 00:03:52 --> 00:03:54 Yeah, I wanted to come off this branch, because I've 49 00:03:54 --> 00:04:03 backtrack just 1, thank you. 50 00:04:03 --> 00:04:09 And then I backtrack up to this branch, and 51 00:04:09 --> 00:04:13 from here we got 0,2,7. 52 00:04:13 --> 00:04:16 And I'm not going to draw the rest of the tree for you here, 53 00:04:16 --> 00:04:18 because I drew it last time, and you don't need to 54 00:04:18 --> 00:04:20 see the whole tree. 55 00:04:20 --> 00:04:30 The point I wanted to make is that for every node, except the 56 00:04:30 --> 00:04:34 leaves, the leaves are the bottom of a tree in this case, 57 00:04:34 --> 00:04:36 computer scientists are weird, right, they draw trees where 58 00:04:36 --> 00:04:40 the root is at the top, and the leaves are at the bottom. 59 00:04:40 --> 00:04:44 And I don't know why, but since time immemorial that is the way 60 00:04:44 --> 00:04:49 computer scientists have drawn trees. 61 00:04:49 --> 00:04:52 That's why we're not biologists, I guess. 62 00:04:52 --> 00:04:54 We don't understand these things. 63 00:04:54 --> 00:04:58 But what I want you to notice is that for each node, except 64 00:04:58 --> 00:05:05 the leaves, the solution for that node can be computed from 65 00:05:05 --> 00:05:10 the solutions from it's children. 66 00:05:10 --> 00:05:17 So in order to look at the solution of this node, I choose 67 00:05:17 --> 00:05:23 one of the solutions of it's children, a or b, is the best 68 00:05:23 --> 00:05:26 solution if I'm here, and of course this is the better 69 00:05:26 --> 00:05:29 of the 2 solutions. 70 00:05:29 --> 00:05:34 If I look at this node, I get to choose its solution as the 71 00:05:34 --> 00:05:39 better of the solution for this node, and this node. 72 00:05:39 --> 00:05:43 All the way up to the top, where when I have to choose the 73 00:05:43 --> 00:05:47 best solution to the whole problem, it's either the best 74 00:05:47 --> 00:05:49 solution to the left node, or the best solution 75 00:05:49 --> 00:05:51 to the right node. 76 00:05:51 --> 00:05:58 This happens to be a binary decision tree. 77 00:05:58 --> 00:06:03 There's nothing magic about there being only two nodes, for 78 00:06:03 --> 00:06:06 the knapsack problem, that's just the way it works out, but 79 00:06:06 --> 00:06:10 there are other problems where there might be multiple 80 00:06:10 --> 00:06:14 decisions to make, more than a or yes or no, but it's always 81 00:06:14 --> 00:06:20 the case here that I have what we last time talked 82 00:06:20 --> 00:06:23 about as what? 83 00:06:23 --> 00:06:36 Optimal sub structure. 84 00:06:36 --> 00:06:42 As I defined it last time, it means that I can solve a 85 00:06:42 --> 00:06:48 problem by finding the optimal solution to smaller 86 00:06:48 --> 00:06:51 sub problems. 87 00:06:51 --> 00:06:54 Classic divide and conquer that we've seen over and 88 00:06:54 --> 00:06:57 over again in the term. 89 00:06:57 --> 00:07:02 Take a hard problem, say well, I can solve it by solving 2 90 00:07:02 --> 00:07:06 smaller problems and combine their solution, and this case, 91 00:07:06 --> 00:07:16 the combining is choosing the best, it's a or b. 92 00:07:16 --> 00:07:20 So then, I went directly from that way of thinking about 93 00:07:20 --> 00:07:26 the problem, to this straightforward, at the top of 94 00:07:26 --> 00:07:31 the slide here, also at the top of your handout, both yesterday 95 00:07:31 --> 00:07:37 and today, a straightforward implementation of max val, that 96 00:07:37 --> 00:07:44 basically just did this. 97 00:07:44 --> 00:07:48 And as you might have guessed, when you're doing this sort of 98 00:07:48 --> 00:07:54 thing, recursion is a very natural way to implement it. 99 00:07:54 --> 00:07:59 We then ran this, demonstrated that it got the right answer on 100 00:07:59 --> 00:08:01 problems that were small enough that we knew with the right 101 00:08:01 --> 00:08:08 answer was, ran it on a big problem, got what we hoped was 102 00:08:08 --> 00:08:10 the right answer, but we had no good way to check it in 103 00:08:10 --> 00:08:17 our heads, but noticed it took a long time to run. 104 00:08:17 --> 00:08:21 And then we asked ourselves, why did it take so long to run? 105 00:08:21 --> 00:08:24 And when we turned on the print statement, what we saw is 106 00:08:24 --> 00:08:31 because it was doing the same thing over and over again. 107 00:08:31 --> 00:08:37 Because we had a lot of the sub-problems were the same. 108 00:08:37 --> 00:08:40 It was as if, when we went through this search tree, we 109 00:08:40 --> 00:08:43 never remembered what we got at the bottom, and we just 110 00:08:43 --> 00:08:46 re-computed things over and over. 111 00:08:46 --> 00:08:50 So that led us to look at memoization, the sort of 112 00:08:50 --> 00:09:03 key idea behind dynamic programming, which says let's 113 00:09:03 --> 00:09:08 remember the work we've done and not do it all over again. 114 00:09:08 --> 00:09:12 We used a dictionary to implement the memo, and that 115 00:09:12 --> 00:09:18 got us to the fast max val, which got called from max val 116 00:09:18 --> 00:09:23 0, because I wanted to make sure I didn't change the 117 00:09:23 --> 00:09:27 specification of max val by introducing this memo that 118 00:09:27 --> 00:09:30 users shouldn't know even exists, because it's part of 119 00:09:30 --> 00:09:35 the implementation, not part of the problem statement. 120 00:09:35 --> 00:09:40 We did that, and all I did was take the original code and keep 121 00:09:40 --> 00:09:43 track of what I've done, and say have I computed this value 122 00:09:43 --> 00:09:50 before, if so, don't compute it again. 123 00:09:50 --> 00:09:54 And that's the key idea that you'll see over and over again 124 00:09:54 --> 00:09:57 as you solve problems with dynamic programming, is you 125 00:09:57 --> 00:10:02 say, have I already solved this problem, if so, let me 126 00:10:02 --> 00:10:05 look up the answer. 127 00:10:05 --> 00:10:08 If I haven't solved the problem, let me solve it, 128 00:10:08 --> 00:10:15 and store the answer away for later reference. 129 00:10:15 --> 00:10:19 Very simple idea, and typically the beauty of dynamic 130 00:10:19 --> 00:10:22 programming as you've seen here, is not only is the 131 00:10:22 --> 00:10:26 idea simple, even the implementation is simple. 132 00:10:26 --> 00:10:30 There are a lot of complicated algorithmic ideas, dynamic 133 00:10:30 --> 00:10:32 programming is not one of them. 134 00:10:32 --> 00:10:35 Which is one of the reasons we teach it here. 135 00:10:35 --> 00:10:37 The other reason we teach it here, in addition to it being 136 00:10:37 --> 00:10:42 simple, is that it's incredibly useful. 137 00:10:42 --> 00:10:46 It's probably among the most useful ideas there is for 138 00:10:46 --> 00:10:50 solving complicated problems. 139 00:10:50 --> 00:10:55 All right, now let's look at it. 140 00:10:55 --> 00:10:58 So here's the fast version, we looked at it last time, I'm not 141 00:10:58 --> 00:11:00 going to bore you by going through the details of it 142 00:11:00 --> 00:11:07 again, but we'll run it. 143 00:11:07 --> 00:11:15 This was the big example we looked at last time, where we 144 00:11:15 --> 00:11:22 had 30 items we could put in to choose from, so when we do it 145 00:11:22 --> 00:11:25 exponentially, it looks like it's 2 to the 30, which is a 146 00:11:25 --> 00:11:33 big number, but when we ran this, it found the answer, 147 00:11:33 --> 00:11:38 and it took only 1805 calls. 148 00:11:38 --> 00:11:43 Now I got really excited about this because, to me it's really 149 00:11:43 --> 00:11:47 amazing, that we've taken a problem that is apparently 150 00:11:47 --> 00:11:51 exponential, and solved it like that. 151 00:11:51 --> 00:11:56 And in fact, I could double the size of the items to choose 152 00:11:56 --> 00:11:59 from, and it would still run like. 153 00:11:59 --> 00:12:02 Eh - I'm not very good at snapping my fingers -- it 154 00:12:02 --> 00:12:04 would still run quickly. 155 00:12:04 --> 00:12:12 All right, so here's the question: have I found a way to 156 00:12:12 --> 00:12:17 solve an inherently exponential problem in linear time. 157 00:12:17 --> 00:12:20 Because what we'll see here, and we saw a little of this 158 00:12:20 --> 00:12:27 last time, as I double the size of the items, I only really 159 00:12:27 --> 00:12:29 roughly double the running time. 160 00:12:29 --> 00:12:32 Quite amazing. 161 00:12:32 --> 00:12:34 So have I done that? 162 00:12:34 --> 00:12:39 Well, I wish I had, because then I would be really famous, 163 00:12:39 --> 00:12:42 and my department head would give me a big raise, and 164 00:12:42 --> 00:12:45 all sorts of wonderful things would follow. 165 00:12:45 --> 00:12:51 But, I'm not famous, and I didn't solve that problem. 166 00:12:51 --> 00:12:53 What's going on? 167 00:12:53 --> 00:12:58 Well this particular algorithm takes roughly, and I'll come 168 00:12:58 --> 00:13:12 back to the roughly question, order (n,s) time, where n is 169 00:13:12 --> 00:13:22 the number of items in the list and s, roughly speaking, is 170 00:13:22 --> 00:13:26 the size of the knapsack. 171 00:13:26 --> 00:13:37 We should also observe, that it takes order and s space. 172 00:13:37 --> 00:13:46 Because it's not free to store all these values. 173 00:13:46 --> 00:13:51 So at one level what I'm doing is trading time for space. 174 00:13:51 --> 00:13:54 It can run faster because I'm using some space 175 00:13:54 --> 00:13:59 to save things. 176 00:13:59 --> 00:14:09 So in this case, we had 30 items and the wait was 40, and, 177 00:14:09 --> 00:14:14 you know, this gives us 1200 which is kind of where we were. 178 00:14:14 --> 00:14:18 And I'm really emphasizing kind of here, because really what 179 00:14:18 --> 00:14:23 I'm using the available size for, is as a proxy for the 180 00:14:23 --> 00:14:28 number of items that can fit in the knapsack. 181 00:14:28 --> 00:14:33 Because the actual running time of this, and the actual space 182 00:14:33 --> 00:14:41 of this algorithm, is governed, interestingly enough, not by 183 00:14:41 --> 00:14:45 the size of the problem alone, but by the 184 00:14:45 --> 00:14:51 size of the solution. 185 00:14:51 --> 00:14:58 And I'm going to come back to that. 186 00:14:58 --> 00:15:06 So how long it takes to run is related to how many items I end 187 00:15:06 --> 00:15:08 up being able to fit into the knapsack. 188 00:15:08 --> 00:15:16 If you think about it, this make sense. 189 00:15:16 --> 00:15:22 An entry is made in the memo whenever an item, and an 190 00:15:22 --> 00:15:27 available size pair is considered. 191 00:15:27 --> 00:15:32 As soon as the available size goes to 0, I know I can't 192 00:15:32 --> 00:15:37 enter any more items into the memo, right? 193 00:15:37 --> 00:15:44 So the number of items I have to remember is related to how 194 00:15:44 --> 00:15:51 many items I can fit in the knapsack. 195 00:15:51 --> 00:15:54 And of course, the amount of running time is exactly the 196 00:15:54 --> 00:15:56 number of things I have to remember, almost 197 00:15:56 --> 00:15:58 exactly, right? 198 00:15:58 --> 00:16:06 So you can see if you think about it abstractly, why the 199 00:16:06 --> 00:16:11 amount of work I have to do here will be proportional to 200 00:16:11 --> 00:16:14 the number of items I can fit in, that is to say, the 201 00:16:14 --> 00:16:17 size of the solution. 202 00:16:17 --> 00:16:23 This is not the way we'd like to talk about complexity. 203 00:16:23 --> 00:16:27 When we talk about the order, or big O, as we keep writing 204 00:16:27 --> 00:16:32 it, of a problem, we always prefer to talk about it in 205 00:16:32 --> 00:16:34 terms of the size of the problem. 206 00:16:34 --> 00:16:41 And that makes sense because in general we don't know the size 207 00:16:41 --> 00:16:45 of the solution until we've solved it. 208 00:16:45 --> 00:16:53 So we'd much rather define big O in terms of the inputs. 209 00:16:53 --> 00:16:58 What we have here is what's called a pseudo-polynomial 210 00:16:58 --> 00:17:04 algorithm. 211 00:17:04 --> 00:17:08 You remember a polynomial algorithm is an algorithm 212 00:17:08 --> 00:17:15 that's polynomial in the size of the inputs. 213 00:17:15 --> 00:17:18 Here we have an algorithm that's polynomial in the 214 00:17:18 --> 00:17:28 size of the solution, hence the qualifier pseudo. 215 00:17:28 --> 00:17:33 More formally, and again this is not crucial to get all the 216 00:17:33 --> 00:17:39 details on this, if we think about a numerical algorithm, a 217 00:17:39 --> 00:17:53 pseudo-polynomial algorithm has running time that's polynomial 218 00:17:53 --> 00:18:02 in the numeric value of the input. 219 00:18:02 --> 00:18:04 I'm using a numeric example because it's easier to 220 00:18:04 --> 00:18:11 talk about it that way. 221 00:18:11 --> 00:18:16 So you might to look at, say, an implementation of factorial, 222 00:18:16 --> 00:18:20 and say its running time is proportional to the numerical 223 00:18:20 --> 00:18:22 value of the number who's factorial. 224 00:18:22 --> 00:18:29 If I'm computing factorial of 8, I'll do 8 operations, Right 225 00:18:29 --> 00:18:34 Factorial of 10, I'll do 10 operations. 226 00:18:34 --> 00:18:39 Now the key issue to think about here, is that as we look 227 00:18:39 --> 00:18:48 at this kind of thing, what we'll see is that, if we look 228 00:18:48 --> 00:18:58 at a numeric value, we know that that's exponential number 229 00:18:58 --> 00:19:12 in the number of digits. 230 00:19:12 --> 00:19:16 So that's the key thing to think about, Right That you can 231 00:19:16 --> 00:19:23 take a problem, and typically, when we're actually formally 232 00:19:23 --> 00:19:28 looking at computational complexity, big O, what we'll 233 00:19:28 --> 00:19:41 define the in terms of, is the size of the coding 234 00:19:41 --> 00:19:48 of the input. 235 00:19:48 --> 00:19:52 The number of bits required to represent the input 236 00:19:52 --> 00:19:59 in the computer. 237 00:19:59 --> 00:20:03 And so when we say something is exponential, we're talking 238 00:20:03 --> 00:20:10 about in terms of the number of bits required to represent it. 239 00:20:10 --> 00:20:14 Now why am I going through all this, maybe I should 240 00:20:14 --> 00:20:18 use the word pseudo-theory? 241 00:20:18 --> 00:20:22 Only because I want you to understand that when we start 242 00:20:22 --> 00:20:27 talking about complexity, it can be really quite subtle. 243 00:20:27 --> 00:20:32 And you have to be very careful to think about what you mean, 244 00:20:32 --> 00:20:35 or you can be very surprised at how long something takes to 245 00:20:35 --> 00:20:38 run, or how much space it uses. 246 00:20:38 --> 00:20:43 And you have to understand the difference between, are you 247 00:20:43 --> 00:20:46 defining the performance in terms of the size of the 248 00:20:46 --> 00:20:49 problem, or the size of the solution. 249 00:20:49 --> 00:20:53 When you talk about the size of the problem, what do you mean 250 00:20:53 --> 00:20:57 by that, is it the length of an array, is it the size of the 251 00:20:57 --> 00:21:01 elements of the array, and it can matter. 252 00:21:01 --> 00:21:07 So when we ask you to tell us something about the efficiency, 253 00:21:07 --> 00:21:12 on for example a quiz, we want you to be very careful not to 254 00:21:12 --> 00:21:17 just write something like, order n squared, but 255 00:21:17 --> 00:21:22 to tell us what n is. 256 00:21:22 --> 00:21:26 For example, the number of elements in the list. 257 00:21:26 --> 00:21:29 But if you have a list of lists, maybe it's not just 258 00:21:29 --> 00:21:31 the number elements in the list, maybe it depends upon 259 00:21:31 --> 00:21:37 what the elements are. 260 00:21:37 --> 00:21:42 So just sort of a warning to try and be very careful as 261 00:21:42 --> 00:21:51 you think about these things, all right. 262 00:21:51 --> 00:21:55 So I haven't done magic, I've given you a really fast way to 263 00:21:55 --> 00:22:02 solve a knapsack problem, but it's still exponential deep 264 00:22:02 --> 00:22:05 down in its heart, in something. 265 00:22:05 --> 00:22:10 All right, in recitation you'll get a chance to look at yet 266 00:22:10 --> 00:22:13 another kind of problem that can be solved by dynamic 267 00:22:13 --> 00:22:17 programming, there are many of them. 268 00:22:17 --> 00:22:21 Before we leave the knapsack problem though, I want to take 269 00:22:21 --> 00:22:24 a couple of minutes to look at a slight variation 270 00:22:24 --> 00:22:26 of the problem. 271 00:22:26 --> 00:22:29 So let's look at this one. 272 00:22:29 --> 00:22:35 Suppose I told you that not only was there a limit on the 273 00:22:35 --> 00:22:38 total weight of the items in the knapsack, but 274 00:22:38 --> 00:22:41 also on the volume. 275 00:22:41 --> 00:22:45 OK, if I gave you a box of balloons, the fact that they 276 00:22:45 --> 00:22:49 didn't weight anything wouldn't mean you couldn't put, you 277 00:22:49 --> 00:22:52 could put lots of them in the knapsack, right? 278 00:22:52 --> 00:22:56 Sometimes it's the volume not the weight that matters, 279 00:22:56 --> 00:22:59 sometimes it's both. 280 00:22:59 --> 00:23:02 So how would we go about solving this problem if I told 281 00:23:02 --> 00:23:04 you not only was there a maximum weight, but there 282 00:23:04 --> 00:23:07 was a maximum volume. 283 00:23:07 --> 00:23:12 Well, we want to go back and attack it exactly the way we 284 00:23:12 --> 00:23:14 attacked it the first time, which was write some 285 00:23:14 --> 00:23:17 mathematical formulas. 286 00:23:17 --> 00:23:21 So you'll remember that when we looked at it, we said that the 287 00:23:21 --> 00:23:29 problem was to maximize the sum from i equals 1 to n, of p sub 288 00:23:29 --> 00:23:34 i, x sub i, maybe it should be 0 to n minus 1, but we 289 00:23:34 --> 00:23:38 won't worry about that. 290 00:23:38 --> 00:23:45 And we had to do it subject to the constraint that the sum 291 00:23:45 --> 00:23:50 from 1 to n of the weight sub i times x sub i, remember x is 0 292 00:23:50 --> 00:23:55 if it was in, 1 if it wasn't, was less than or equal to the 293 00:23:55 --> 00:23:59 cost, as I wrote it this time, which was the maximum 294 00:23:59 --> 00:24:02 allowable weight. 295 00:24:02 --> 00:24:06 What do we do if we want to add volume, is an issue? 296 00:24:06 --> 00:24:07 Does this change? 297 00:24:07 --> 00:24:10 Does the goal change? 298 00:24:10 --> 00:24:11 You're answering. 299 00:24:11 --> 00:24:13 Answer out -- no one else can see you shake your head. 300 00:24:13 --> 00:24:14 STUDENT: No. 301 00:24:14 --> 00:24:15 PROFESSOR: No. 302 00:24:15 --> 00:24:18 The goal does not change, it's still the same goal. 303 00:24:18 --> 00:24:19 What changes? 304 00:24:19 --> 00:24:22 STUDENT: The constraints. 305 00:24:22 --> 00:24:24 PROFESSOR: Yeah, and you don't get another bar. 306 00:24:24 --> 00:24:25 The constraint has to change. 307 00:24:25 --> 00:24:28 I've added a constraint. 308 00:24:28 --> 00:24:31 And, what's the constraint I've added? 309 00:24:31 --> 00:24:33 Somebody else -- yeah? 310 00:24:33 --> 00:24:36 STUDENT: You can't exceed the volume that the 311 00:24:36 --> 00:24:37 knapsack can hold. 312 00:24:37 --> 00:24:38 PROFESSOR: Right, but can you state in this 313 00:24:38 --> 00:24:39 kind of formal way? 314 00:24:39 --> 00:24:43 STUDENT: [INAUDIBLE] 315 00:24:43 --> 00:24:44 PROFESSOR: -- sum from i equals 1 to n -- 316 00:24:44 --> 00:24:45 STUDENT: [INAUDIBLE] 317 00:24:45 --> 00:24:55 PROFESSOR: Let's say v sub i, x sub i, is less than or equal 318 00:24:55 --> 00:24:59 to, we'll write k for the total allowable volume. 319 00:24:59 --> 00:25:02 Exactly. 320 00:25:02 --> 00:25:10 So the thing to notice here, is it's actually quite a simple 321 00:25:10 --> 00:25:13 little change we've made. 322 00:25:13 --> 00:25:18 I've simply added this one extra constraint, nice thing 323 00:25:18 --> 00:25:21 about thinking about it this way is it's easy to think about 324 00:25:21 --> 00:25:25 it, and what do you think I'll have to do if I want to 325 00:25:25 --> 00:25:28 go change the code? 326 00:25:28 --> 00:25:32 I'm not going to do it for you, but what would I think about 327 00:25:32 --> 00:25:35 doing when I change the code? 328 00:25:35 --> 00:25:38 Well, let's look at the simple version first, because 329 00:25:38 --> 00:25:39 it's easier to look at. 330 00:25:39 --> 00:25:42 At the top. 331 00:25:42 --> 00:25:45 Well basically, all I'd have to do is go through and find 332 00:25:45 --> 00:25:51 every place I checked the constraint, and change it. 333 00:25:51 --> 00:25:55 To incorporate the new constraint. 334 00:25:55 --> 00:25:58 And when I went to the dynamic programming problem, what would 335 00:25:58 --> 00:26:02 I have to do, what would change? 336 00:26:02 --> 00:26:07 The memo would have to change, as well as the checks, right? 337 00:26:07 --> 00:26:13 Because now, I not only would have to think about how much 338 00:26:13 --> 00:26:17 weight did I have available, but I have to think about how 339 00:26:17 --> 00:26:20 much volume did I have available. 340 00:26:20 --> 00:26:27 So whereas before, I had a mapping from the item and the 341 00:26:27 --> 00:26:31 weight available, now I would have to have it from a tuple 342 00:26:31 --> 00:26:35 of the weight and the volume. 343 00:26:35 --> 00:26:38 Very small changes. 344 00:26:38 --> 00:26:41 That's one of the things I want you to sort of understand as we 345 00:26:41 --> 00:26:47 look at algorithms, that they're very general, and once 346 00:26:47 --> 00:26:51 you've figured out how to solve one problem, you can often 347 00:26:51 --> 00:26:54 solve another problem by a very straightforward reduction 348 00:26:54 --> 00:26:59 of this kind of thing. 349 00:26:59 --> 00:27:03 All right, any questions about that. 350 00:27:03 --> 00:27:03 Yeah? 351 00:27:03 --> 00:27:05 STUDENT: I had a question about what you were 352 00:27:05 --> 00:27:06 talking about just before. 353 00:27:06 --> 00:27:06 PROFESSOR: The pseudo-polynomial? 354 00:27:06 --> 00:27:07 STUDENT: Yes. 355 00:27:07 --> 00:27:07 PROFESSOR: Ok. 356 00:27:07 --> 00:27:10 STUDENT: So, how do you come to a conclusion as to which you 357 00:27:10 --> 00:27:15 should use then, if you can determine the size based on 358 00:27:15 --> 00:27:22 solution, or based on input, so how do you decide? 359 00:27:22 --> 00:27:23 PROFESSOR: Great question. 360 00:27:23 --> 00:27:27 So the question is, how do you choose an algorithm, why would 361 00:27:27 --> 00:27:30 I choose to use a pseudo-polynomial algorithm 362 00:27:30 --> 00:27:33 when I don't know how big the solution is likely to be, I 363 00:27:33 --> 00:27:36 think that's one way to think about it. 364 00:27:36 --> 00:27:42 Well, so if we think about the knapsack problem, we can look 365 00:27:42 --> 00:27:46 at it, and we can ask ourselves, well first of all we 366 00:27:46 --> 00:27:49 know that the brute force exponential solution is 367 00:27:49 --> 00:27:55 going to be a loser if the number of items is large. 368 00:27:55 --> 00:27:58 Fundamentally in this case, what I could look at is the 369 00:27:58 --> 00:28:03 ratio of the number of items to the size of the knapsack, say 370 00:28:03 --> 00:28:08 well, I've got lots items to choose from, I probably 371 00:28:08 --> 00:28:10 won't put them all in. 372 00:28:10 --> 00:28:13 But even if I did, it would still only be 373 00:28:13 --> 00:28:17 30 of them, right? 374 00:28:17 --> 00:28:18 It's hard. 375 00:28:18 --> 00:28:22 Typically what we'll discover is the pseudo-polynomial 376 00:28:22 --> 00:28:33 algorithms are usually better, and in this case, never worse. 377 00:28:33 --> 00:28:37 So this will never be worse than the brute force one. if I 378 00:28:37 --> 00:28:40 get really unlucky, I end up checking the same number of 379 00:28:40 --> 00:28:44 things, but I'd have to be really, it'd have to be a very 380 00:28:44 --> 00:28:47 strange structure to the problem. 381 00:28:47 --> 00:28:54 So it's almost always the case that, if you can find a 382 00:28:54 --> 00:29:01 solution that uses dynamic programming, it will be better 383 00:29:01 --> 00:29:05 than the brute force, and certainly not, well, maybe use 384 00:29:05 --> 00:29:09 more space, but not use more time. 385 00:29:09 --> 00:29:13 But there is no magic, here, and so the question you asked 386 00:29:13 --> 00:29:15 is a very good question. 387 00:29:15 --> 00:29:20 And it's sometimes the case in real life that you don't know 388 00:29:20 --> 00:29:23 which is the better algorithm on the data you're actually 389 00:29:23 --> 00:29:26 going to be crunching. 390 00:29:26 --> 00:29:31 And you pays your money and you takes your chances, right? 391 00:29:31 --> 00:29:35 And if the data is not what you think it's going to be, you may 392 00:29:35 --> 00:29:38 be wrong in your choice, so you typically do have to spend some 393 00:29:38 --> 00:29:41 time thinking about it, what's the data going 394 00:29:41 --> 00:29:42 to actually look like. 395 00:29:42 --> 00:29:45 Very good question. 396 00:29:45 --> 00:29:48 Anything else? 397 00:29:48 --> 00:29:55 All right, a couple of closing points before we leave this, 398 00:29:55 --> 00:29:59 things I would like you to remember. 399 00:29:59 --> 00:30:09 In dynamic programming, one of the things that's going on is 400 00:30:09 --> 00:30:17 we're trading time for space. 401 00:30:17 --> 00:30:21 Dynamic programming is not the only time we do that. 402 00:30:21 --> 00:30:25 We've solved a lot of problems that way, in fact, by 403 00:30:25 --> 00:30:30 trading time for space. 404 00:30:30 --> 00:30:32 Table look-up, for example, right, that if you're going to 405 00:30:32 --> 00:30:35 have trig tables, you may want to compute them all at once 406 00:30:35 --> 00:30:38 and then just look it up. 407 00:30:38 --> 00:30:40 So that's one thing. 408 00:30:40 --> 00:30:58 Two, don't be intimidated by exponential problems. 409 00:30:58 --> 00:31:00 There's a tendency for people to say, oh this problem's 410 00:31:00 --> 00:31:03 exponential, I can't solve it. 411 00:31:03 --> 00:31:06 Well, I solve 2 or 3 exponential problems before 412 00:31:06 --> 00:31:10 breakfast every day. 413 00:31:10 --> 00:31:13 You know things like, how to find my way to the bathroom is 414 00:31:13 --> 00:31:20 inherently exponential, but I manage to solve it anyway. 415 00:31:20 --> 00:31:21 Don't be intimidated. 416 00:31:21 --> 00:31:27 Even though it is apparently exponential, a lot of times 417 00:31:27 --> 00:31:31 you can actually solve it much, much faster. 418 00:31:31 --> 00:31:36 Other issues. 419 00:31:36 --> 00:31:53 Three: dynamic programming is broadly useful. 420 00:31:53 --> 00:31:58 Whenever you're looking at a problem that seems to have a 421 00:31:58 --> 00:32:02 natural recursive solution, think about whether you 422 00:32:02 --> 00:32:07 can attack it with dynamic programming. 423 00:32:07 --> 00:32:10 If you've got this optimal substructure, and overlapping 424 00:32:10 --> 00:32:15 sub-problems, you can use dynamic programming. 425 00:32:15 --> 00:32:19 So it's good for knapsacks, it's good for shortest paths, 426 00:32:19 --> 00:32:22 it's good for change-making, it's good for a whole 427 00:32:22 --> 00:32:25 variety of problems. 428 00:32:25 --> 00:32:28 And so keep it in your toolbox, and when you have a hard 429 00:32:28 --> 00:32:32 problem to solve, one of the first questions you should ask 430 00:32:32 --> 00:32:35 yourself is, can I use dynamic programming? 431 00:32:35 --> 00:32:40 It's great for string-matching problems of a whole variety. 432 00:32:40 --> 00:32:43 It's hugely useful. 433 00:32:43 --> 00:32:48 And finally, I want you to keep in mind the whole concept 434 00:32:48 --> 00:32:54 of problem reduction. 435 00:32:54 --> 00:33:00 I started with this silly description of a burglar, and 436 00:33:00 --> 00:33:04 said : Well this is really the knapsack problem, and now I can 437 00:33:04 --> 00:33:10 go Google the knapsack problem and find code to solve it. 438 00:33:10 --> 00:33:13 Any time you can reduce something to a previously 439 00:33:13 --> 00:33:19 solved problem, that's good. 440 00:33:19 --> 00:33:25 And this is a hugely important lesson to learn. 441 00:33:25 --> 00:33:28 People tend not to realize that the first question you should 442 00:33:28 --> 00:33:31 always ask yourself, is this really just something that's 443 00:33:31 --> 00:33:34 well-known in disguise? 444 00:33:34 --> 00:33:36 Is it a shortest path problem? 445 00:33:36 --> 00:33:38 Is it a nearest neighbor problem? 446 00:33:38 --> 00:33:42 Is it what string is this most similar to problem? 447 00:33:42 --> 00:33:47 There are scores of well-understood problems, but 448 00:33:47 --> 00:33:52 only really scores, it's not thousands of them, and over 449 00:33:52 --> 00:33:56 time you'll build up a vocabulary of these problems, 450 00:33:56 --> 00:33:59 and when you see something in your domain, be it physics or 451 00:33:59 --> 00:34:04 biology or anything else, linguistics, the question you 452 00:34:04 --> 00:34:10 should ask is can I transform this into an existing problem? 453 00:34:10 --> 00:34:14 Ok, double line. 454 00:34:14 --> 00:34:16 If there are no questions I'm going to make a dramatic 455 00:34:16 --> 00:34:19 change in topic. 456 00:34:19 --> 00:34:24 We're going to temporarily get off of this more esoteric 457 00:34:24 --> 00:34:28 stuff, and go back to Python. 458 00:34:28 --> 00:34:33 And for the next, off and on for the next couple of weeks, 459 00:34:33 --> 00:34:51 we'll be talking about Python and program organization. 460 00:34:51 --> 00:34:58 And what I want to be talking about is modules of one sort, 461 00:34:58 --> 00:35:01 and of course that's because what we're interested 462 00:35:01 --> 00:35:06 in is modularity. 463 00:35:06 --> 00:35:10 How do we take a complex program, again, divide and 464 00:35:10 --> 00:35:14 conquer, I feel like a 1-trick pony, I keep repeating the same 465 00:35:14 --> 00:35:16 thing over and over again. 466 00:35:16 --> 00:35:21 Divide and conquer to make our programs modular so we can 467 00:35:21 --> 00:35:23 write them a little piece at a time and understand them a 468 00:35:23 --> 00:35:26 little piece at a time. 469 00:35:26 --> 00:35:35 Now I think of a module as a collection of 470 00:35:35 --> 00:35:44 related functions. 471 00:35:44 --> 00:35:47 We've already seen these, and we're going to refer to the 472 00:35:47 --> 00:36:01 functions using dot notation. 473 00:36:01 --> 00:36:04 We've been doing this all term, right, probably somewhere 474 00:36:04 --> 00:36:13 around lecture 2, we said import math, and then somewhere 475 00:36:13 --> 00:36:17 in our program we wrote something like math dot sqrt of 476 00:36:17 --> 00:36:25 11, or some other number. 477 00:36:25 --> 00:36:28 And the good news was we didn't have to worry about how math 478 00:36:28 --> 00:36:31 did square root or anything like that, we just got 479 00:36:31 --> 00:36:33 it and we used it. 480 00:36:33 --> 00:36:54 Now we have the dot notation to avoid name conflicts. 481 00:36:54 --> 00:36:59 Imagine, for example, that in my program I wrote something 482 00:36:59 --> 00:37:05 like import set, because somebody had written a module 483 00:37:05 --> 00:37:11 that implements mathematical sets, and somewhere else I'd 484 00:37:11 --> 00:37:16 written something like import table, because someone had 485 00:37:16 --> 00:37:19 something that implemented look-up tables of some 486 00:37:19 --> 00:37:24 sort, something like dictionaries, for example. 487 00:37:24 --> 00:37:28 And then, I wanted to ask something like membership. 488 00:37:28 --> 00:37:31 Is something in the set, or is something in the table? 489 00:37:31 --> 00:37:34 Well, what I would have written is something 490 00:37:34 --> 00:37:43 like table dot member. 491 00:37:43 --> 00:37:48 And then the element and maybe the table. 492 00:37:48 --> 00:37:52 And the dot notation was used to disambiguate, because I want 493 00:37:52 --> 00:37:54 the member operation from table, not the member 494 00:37:54 --> 00:37:56 one from set. 495 00:37:56 --> 00:38:00 This was important because the people who implemented table 496 00:38:00 --> 00:38:04 and set might never have met each other, and so they can 497 00:38:04 --> 00:38:06 hardly have been expected not to have used the same name 498 00:38:06 --> 00:38:10 somewhere by accident. 499 00:38:10 --> 00:38:14 Hence the use of the dot notation. 500 00:38:14 --> 00:38:20 I now want to talk about a particular kind of module, and 501 00:38:20 --> 00:38:23 those are the modules that include classes or 502 00:38:23 --> 00:38:32 that are classes. 503 00:38:32 --> 00:38:36 This is a very important concept as we'll see, it's why 504 00:38:36 --> 00:38:39 MIT calls things like 6.00 subjects, so that they don't 505 00:38:39 --> 00:38:45 get confused with classes in Python, something we really 506 00:38:45 --> 00:38:46 need to remember here. 507 00:38:46 --> 00:38:49 Now they can be used in different ways, and they 508 00:38:49 --> 00:38:52 have been historically used in different ways. 509 00:38:52 --> 00:38:57 In this subject we're going to emphasize using classes in the 510 00:38:57 --> 00:39:05 context of what's called object-oriented programming. 511 00:39:05 --> 00:39:10 And if you go look up at Python books on the web, or Java books 512 00:39:10 --> 00:39:13 on the web, about 80% of them will include the word 513 00:39:13 --> 00:39:17 object-oriented in their title. 514 00:39:17 --> 00:39:20 Object-oriented Python programming for computer games, 515 00:39:20 --> 00:39:24 or who knows what else. 516 00:39:24 --> 00:39:30 And we're going to use this object-oriented programming, 517 00:39:30 --> 00:39:38 typically to create something called data abstractions. 518 00:39:38 --> 00:39:40 And over the next couple of days, you'll see what we 519 00:39:40 --> 00:39:43 mean by this in detail. 520 00:39:43 --> 00:39:48 A synonym for this is an abstract data type. 521 00:39:48 --> 00:39:52 You'll see both terms used on the web, and the literature 522 00:39:52 --> 00:39:56 etc., and think of them as synonyms. 523 00:39:56 --> 00:39:59 Now these ideas of classes, object-oriented programming, 524 00:39:59 --> 00:40:04 data abstraction, are about 40 years old, they're 525 00:40:04 --> 00:40:05 not new ideas. 526 00:40:05 --> 00:40:09 But they've only been really widely accepted in practice 527 00:40:09 --> 00:40:12 for 10 to 15 years. 528 00:40:12 --> 00:40:16 It was in the mid-70's, people began to write articles 529 00:40:16 --> 00:40:22 advocating this style of programming, and actually 530 00:40:22 --> 00:40:26 building programming languages, notably Smalltalk and Clue at 531 00:40:26 --> 00:40:30 MIT in fact, that provided linguistic support for the 532 00:40:30 --> 00:40:34 ideas of data abstraction and object-oriented programming. 533 00:40:34 --> 00:40:40 But it really wasn't until, I would say, the arrival of Java 534 00:40:40 --> 00:40:42 that object-oriented programming caught the 535 00:40:42 --> 00:40:47 popular attention. 536 00:40:47 --> 00:40:58 And then Java, C++ , Python of, course. 537 00:40:58 --> 00:41:02 And today nobody advocates a programming language 538 00:41:02 --> 00:41:07 that does not support it in some sort of way. 539 00:41:07 --> 00:41:10 So what is this all about? 540 00:41:10 --> 00:41:27 What is an object in object-oriented programming? 541 00:41:27 --> 00:41:49 An object is a collection of data and functions. 542 00:41:49 --> 00:41:53 In particular functions that operate on the data, perhaps 543 00:41:53 --> 00:41:58 on other data as well. 544 00:41:58 --> 00:42:05 The key idea here is to bind together the data and the 545 00:42:05 --> 00:42:10 functions that operate on that data as a single thing. 546 00:42:10 --> 00:42:12 Now typically that's probably not the way you've been 547 00:42:12 --> 00:42:14 thinking about things. 548 00:42:14 --> 00:42:18 When you think about an int or a float or a dictionary or a 549 00:42:18 --> 00:42:21 list, you knew that there were functions that 550 00:42:21 --> 00:42:23 operated on them. 551 00:42:23 --> 00:42:27 But when you pass a parameter say, a list, you didn't think 552 00:42:27 --> 00:42:30 that you were not only passing the list, you were also 553 00:42:30 --> 00:42:34 passing the functions that operate on the list. 554 00:42:34 --> 00:42:37 In fact you are. 555 00:42:37 --> 00:42:45 It often doesn't matter, but it sometimes really does. 556 00:42:45 --> 00:42:50 The advantage of that, is that when you pass an object to 557 00:42:50 --> 00:42:56 another part of the program, that part of the program also 558 00:42:56 --> 00:43:03 gets the ability to perform operations on the object. 559 00:43:03 --> 00:43:06 Now when the only types we're dealing with are the built-in 560 00:43:06 --> 00:43:10 types, the ones that came with the programming language, 561 00:43:10 --> 00:43:12 that doesn't really matter. 562 00:43:12 --> 00:43:16 Because, well, the programming language means everybody has 563 00:43:16 --> 00:43:19 access to those operations. 564 00:43:19 --> 00:43:23 But the key idea here is that we're going to be generating 565 00:43:23 --> 00:43:33 user-defined types, we'll invent new types, and as we do 566 00:43:33 --> 00:43:39 that we can't assume that if as we pass objects of that type 567 00:43:39 --> 00:43:43 around, that the programming language is giving us the 568 00:43:43 --> 00:43:51 appropriate operations on that type. 569 00:43:51 --> 00:43:55 This combining of data and functions on that data 570 00:43:55 --> 00:44:00 is a very essence of object-oriented programming. 571 00:44:00 --> 00:44:03 That's really what defines it. 572 00:44:03 --> 00:44:13 And the word that's often used for that is encapsulation. 573 00:44:13 --> 00:44:18 Think of it as we got a capsule, like a pill or 574 00:44:18 --> 00:44:23 something, and in that capsule we've got data and a bunch of 575 00:44:23 --> 00:44:32 functions, which as we'll see are called methods. 576 00:44:32 --> 00:44:34 Don't worry, it doesn't matter that they're called methods, 577 00:44:34 --> 00:44:43 it's a historical artifact. 578 00:44:43 --> 00:44:46 All right, so what's an example of this? 579 00:44:46 --> 00:44:51 Well, we could create a circle object, that would store a 580 00:44:51 --> 00:44:56 representation of the circle and also provide methods to 581 00:44:56 --> 00:45:01 operate on it, for example, draw the circle on the screen, 582 00:45:01 --> 00:45:06 return the area of the circle, inscribe it in a square, who 583 00:45:06 --> 00:45:09 knows what you want to do with it. 584 00:45:09 --> 00:45:14 As we talk about this, as people talk about this, in the 585 00:45:14 --> 00:45:22 context of our object-oriented programming, they typically 586 00:45:22 --> 00:45:27 will talk about it in terms of message pass, a message 587 00:45:27 --> 00:45:42 passing metaphor. 588 00:45:42 --> 00:45:45 I want to mention it's just a metaphor, just a way of 589 00:45:45 --> 00:45:50 thinking about it, it's not anything very deep here. 590 00:45:50 --> 00:45:56 So, the way people will talk about this, is one object can 591 00:45:56 --> 00:46:01 pass a message to another object, and the receiving 592 00:46:01 --> 00:46:07 object responds by executing one of its methods 593 00:46:07 --> 00:46:08 on the object. 594 00:46:08 --> 00:46:13 So let's think about lists. 595 00:46:13 --> 00:46:17 So if l is a list, I can call something like s 596 00:46:17 --> 00:46:21 dot sort, l dot sort. 597 00:46:21 --> 00:46:22 You've seen this. 598 00:46:22 --> 00:46:32 This says, pass the object l the message sort, and that 599 00:46:32 --> 00:46:36 message says find the method sort, and apply it to the 600 00:46:36 --> 00:46:41 object l, in this case mutating the object so that the elements 601 00:46:41 --> 00:46:47 are now in sorted order. 602 00:46:47 --> 00:46:55 If c is a circle, I might write something like c dot area. 603 00:46:55 --> 00:46:59 And this would say, pass to the object denoted by the variable 604 00:46:59 --> 00:47:07 c, the message area, which says execute a method called area, 605 00:47:07 --> 00:47:10 and in this case the method might return a float, rather 606 00:47:10 --> 00:47:14 than have a side-effect. 607 00:47:14 --> 00:47:18 Now again, don't get carried away, I almost didn't talk 608 00:47:18 --> 00:47:22 about this whole message-passing paradigm, but 609 00:47:22 --> 00:47:25 it's so pervasive in the world I felt you needed 610 00:47:25 --> 00:47:27 to hear about it. 611 00:47:27 --> 00:47:30 But it's nothing very deep, and if you want to not think about 612 00:47:30 --> 00:47:35 messages, and just think oh, c has a method area, a circle has 613 00:47:35 --> 00:47:38 a method area, and c as a circle will apply it and do 614 00:47:38 --> 00:47:44 what it says, you won't get in any trouble at all. 615 00:47:44 --> 00:47:56 Now the next concept to think about here, is the 616 00:47:56 --> 00:48:03 notion of an instance. 617 00:48:03 --> 00:48:09 So we've already thought about, we create instances of types, 618 00:48:09 --> 00:48:12 so when we looked at lists, and we looked at the notion of 619 00:48:12 --> 00:48:16 aliasing, we used the word instance, and said this is 1 620 00:48:16 --> 00:48:20 object, this is another object, each of those objects is 621 00:48:20 --> 00:48:27 an instance of type list. 622 00:48:27 --> 00:48:31 So now that gets us to a class. 623 00:48:31 --> 00:48:51 A class is a collection of objects with 624 00:48:51 --> 00:49:05 characteristics in common. 625 00:49:05 --> 00:49:08 So you can think of class list. 626 00:49:08 --> 00:49:12 What is the characteristic that all objects of class list have 627 00:49:12 --> 00:49:16 in common, all instances of class list? it's the set of 628 00:49:16 --> 00:49:19 methods that can be applied to lists. 629 00:49:19 --> 00:49:26 Methods like sort, append, other things. 630 00:49:26 --> 00:49:30 So you should think of all of the built-in types we've 631 00:49:30 --> 00:49:35 talked about as actually just built-in classes, like 632 00:49:35 --> 00:49:38 dictionaries, lists, etc. 633 00:49:38 --> 00:49:43 The beauty of being able to define your own class is you 634 00:49:43 --> 00:49:47 can now extend the language. 635 00:49:47 --> 00:49:50 So if, for example, you're in the business, God forbid, of 636 00:49:50 --> 00:49:55 writing financial software today, you might decide, I'd 637 00:49:55 --> 00:50:00 really like to have a class called tanking stock, or bad 638 00:50:00 --> 00:50:03 mortgage, or something like that or mortgage, right? 639 00:50:03 --> 00:50:07 Which would have a bunch of operations, like, I won't go 640 00:50:07 --> 00:50:08 into what they might be. 641 00:50:08 --> 00:50:11 But you'd like to write your program not in terms of floats 642 00:50:11 --> 00:50:15 and ints and lists, but in terms of mortgages, and CDOs, 643 00:50:15 --> 00:50:18 and all of the objects that you read about in the paper, 644 00:50:18 --> 00:50:20 the types you read about. 645 00:50:20 --> 00:50:23 And so you get to build your own special purpose programming 646 00:50:23 --> 00:50:26 language that helped you solve your problems in biology or 647 00:50:26 --> 00:50:31 finance or whatever, and we'll pick up here again on Tuesday. 648 00:50:31 --> 00:50:33