While we have some breaking news folks as journalist Haley Mason reports Greg McMichael Travis McMichael and William Bryan are found guilty of murder for shooting and killing Ahmed Arbery on February 23rd 2020 in Brunswick, Georgia. They now face life in prison. We the jury find the defendant Travis McMichael guilty. I'm gonna ask that whoever just made it out first be removed from the court please. To see his murder is actually be found guilty. I think that is worthy of cheering. Now I do want to go to a quick clip of his mother Wanda Cooper reacting. We the jury find the defendant William R. Bryan guilty. Signed this 24th day of November by the foreperson. Go ahead and see. Court having read the verdicts and accepted the verdicts. Anything from the state. Yeah, I mean, this is not going to bring back her son, but to get a sense of justice. Hopefully now this will help her feel at peace. I mean, you'll never overcome losing loved one, but this is at least hopefully the beginning of the healing process for her. And the one thing that stood out to me is how this guilty verdict may have never happened had there not been so much outraged over this case because Ahmed Arbery was murdered and it wasn't until months later that his murderers were actually arrested. So for more on this, we go to the Washington Post's Tim Craig and Hannah Knowles who explained the three men who chased and killed Ahmed Arbery in coastal Georgia last year were convicted of murder Wednesday in a case that once went 74 days without arrests and that many saw as a test of racial bias in the justice system. The decision was read to the court shortly after 1.30 p.m. after less than two days of deliberations. Members of Arbery's family cried out with joy. Travis McMichael, his father Greg McMichael and their neighbor, William Roddy Bryan, were all convicted of felony murder in the shooting of Arbery, a 25-year-old black man, meaning they committed felonies that caused his death. They were also found guilty of aggravated assault, false imprisonment, and attempt to falsely imprison. But Bryan and the elder McMichael were acquitted of malice murder, which involves intent to kill. Each defendant now faces a potential penalty of life in prison without parole. All men still face federal hate crime charges. A leaked video of the February 23rd, 2020 shooting thrust the case into the national spotlight just weeks before the murder of George Floyd by a white police officer in Minneapolis ignited mass protests against police brutality and racism. Arbery's killing became a rallying point for the Black Lives Matter movement, as protesters said Arbery was racially profiled while jogging and accused authorities of brushing his death aside. Now let's just pause for a moment and let the details sink in. They murdered Ahmed Arbery and they were not arrested until 74 days later. And if this case didn't go viral, if that video didn't go viral, we might not see this guilty verdict today. Let that sink in, that is absolutely insane. They murdered someone and they weren't arrested until 74 days later. Now I'm glad knowing that they are going to spend the rest of their lives behind bars. They deserve that. But they got away with murder for months. And I mean, imagine if this didn't go viral. They might still be walking free today. That is astonishing. It's just it's a really depressing thing to think about. Now it was evident from the beginning that the defense had no case whatsoever. This was an actual argument that the defense attorney made during the closing statement. Turning Ahmed Arbery into a victim. After the choices that he made does not reflect the reality of what brought Ahmad Arbery to Sattila shores in his khaki shorts with no socks to cover his long dirty toenails. Absolutely unreal and despicable. And you can tell that they were grasping at straws. Now the crux of the defense's argument is as follows as told by the Washington Post. Lawyers for the defendants said the men were attempting a legitimate citizen's arrest and argued that race played no role. Sure it didn't. So, you know, with all of these cases, when we actually see justice, that's surprising to me, even if the facts weren't on their side, if the evidence wasn't on their side, I still doubted this outcome. But I'm glad that we have this outcome. I'm glad that there's justice. But still it's deeply sad because Ahmed Arbery should be here right now. He should be here right now. So there's justice for his family. And this is the start of the healing process for his mom. But he shouldn't be gone in the first place. So overall, you know, I think that it's a relief knowing that they were found guilty and they will be going to jail. But it's still deeply sad to think about the fact that Ahmed Arbery is not here overall. So, you know, this is a breaking story. If more details emerge, then, you know, I'll follow up. But sentencing will follow. But for now, we know that they were found guilty. And that's, that's, I guess you could say a relief.


Mountain Top Sports made its way to Pond Creek and Phelps on Friday night for the opening week of high school football action in Kentucky. The defending class 3A state champion, Pirates, led by running back Isaac Dixon and quarterback Brent Coleman, powered the Pirates to a 33-13 victory over Pulaski County on the new turf at Cam Stadium, a wood field. Belfrey will return to action next Friday night when they visit Hillard Howard Field for a matchup with defending class 1A champion, Pike Phil. Mountain Top Sports will live stream the game on mountain-topsports.com. Visit the page for details on how you can view the game. Meanwhile, Martin County and Phelps combined for 92 points at Marty Casey Stadium as the Cardinals scored a 52-40 victory.  After opening night games had McGuffin County rolling past Betsy Lane 36-8. Pantsville came from behind to beat East Jessamine 39-24. Defending class 4A champion, Johnson Central went on the road to Log Mountain and cruised past Bell County 36-0. Shelby Valley built a 40-0 lead against Jackson County and the Wildcats went on to win 46-16. Letcher Central rallied to beat Rock Castle County 27-8. Perry Central knocked off Pike Central 37-23 and Powell County etched Prestonsburg. Two games are on tap Saturday as Pike will journey to Raceland to face the Rams in the 7.30pm kickoff on WPKE 98.1 FM and Floyd Central tackles Hazard at Perry Central beginning at 8pm. With Mountain Top Sports, I'm Cody Davis.


It's true, Israel is a Jewish state but alongside the Jews there are also Muslim Arabs, Christians and Jews along with also other ethnicities including a small and special sect, the Circassian sect. The Circassians are a Caucasian people consisting of 12 tribes who live mainly in the North Caucasus, Russia, Turkey and the rest of the Middle East. In Israel, there is a small community of Circassians who live mainly in two villages in the Galilee, Kfar Kama in the Lower Galilee and Rehaniye in the Upper Galilee. Most Circassians, including those in Israel, belong to the religion of Islam and one of them is the Israeli MMA fighter Yannal Ashmoos aka the Red Fox. Why this nickname and who chose it? I was working at the factory back then with a friend so I had my first fight amateur so they told us to come up with some nickname so you know we were thinking about like couple stuff came up but eventually he said like Red Fox and I just liked it. Yannal represents Israel in the largest competitive fighting league in the world, UFC. He's only the second Israeli there. I represent Israel because I was born here. I'm a Circassian, I'm a Muslim so I represent three of them. Everyone should be happy for it, instead of fighting each other it's like a piece. Why to make a fight from nothing, right? He won his debut fight in the UFC in one minute and 15 seconds. Even though his opponent was considered a favorite both because of his size and physicality but also because the crowd strongly favored the opponent. Still Yannal defeated him in a knockout. Because Yannal represents Israel, many people assume he is Jewish but believe it or not he's unfortunately been in the receiving end of some pretty disturbing anti-Semitism. Every time they post something of mine they say like you know a Jewish guy is going to fight or stuff like that you know he's going to lose that Jewish guy something like that. The Circassian guy says that they say to him no he's a Muslim, he's a Circassian he's not Jewish but he's an Israeli guy like they protect me so I don't have a problem with that you know no matter what you do people will always say something about you so just do what you believe in right say what you believe in and that's it. Despite all the obstacles nothing will stop Yannal and he will continue to represent the country and the Circassian community with dignity on his way to the top. Tell me what is your goals and dreams? My dream was to get to UFC first of all so I made it I did it now I want to go for the build. I know it's going to take time like two years three years but the consistency is the key so you just need to keep to train and fighting all the time it's going to come eventually if you're like serious you will get there so that's my dream and my goals to be healthy all the time. Whatever the situation is just try your best if you love it go for it because there's going to be a lot of obstacles you know in the way that's going to make you sometimes think why is it good I need to do this but eventually if you keep going at it you will get it no matter how much time it's going to take you'll get there so that's like never give up that's that's my message. Israel is a country of equality and partnership between different cultures and religions and that's part of its beauty on the other hand Israel is a strong country with real fighters so don't mess with us.


What I would like to do is to, you know, I also have a presentation to give you to the discussing about the overlay, right. But I would like to rub it up a little bit so that, you know, we will take you through some example that I have for the class covering from the beginning when we start a very, very simple assignment. Okay, then going through the simdising, going through the DM8, how do we do the DM8, how do we do the DM8 list, and we will discuss about if we have a large array of data, okay, in the main memory, and how do we DM8 that memory down to the local store so our local store program can run that one and through which techniques, the DM8 list, the multi-bufferings, and also this the discussion of after we exceeding 256k bytes or 200k bytes, who is going to take care of that one. Don't forget, the owner of the operations and DM8 was handed by the MFC. The MFC was handed that once we do the MFC list commands, the MFC hardware will handle the supplying, using the data and address from that list. We will supply the data to your programs and we'll show you how to do that one. Okay, let's say that I will take you a tour here, right, and bear with me, you know, that's some of the things that we may have seen before or may not, right. Let's say that we have a very straightforward program, right. We all understand this code. We have a float of ABC, right, and then we have a main program, so we do a equal to b plus c and it will return to zero. Okay, and now we'll take you through and ask you to show me how to convert these programs to an SPU program or the PPU or whatever, the embedded program we talked about the last two days, right. Today, if you have any questions, I will be, Hema and I will respond to you and answer your question, right, so we quit over here. All right, so now what we need to do, this is any program. What we need to do in order to make this one is a PPU program. Just compile the ASA, redo this, what compiler that we use, XSC, GCC, SPU minus GCC, right, T2.C, correct, everyone to put down. T1.C, fine, that's good, right. Oh, okay, I have a T1.C and T1.C, we'll show you what it, all right, so we're okay, right, do a list, we have something added out. Can we execute this program now? No, not yet, right, we have to bring it over simulator, fine, we don't worry about that. Okay, now let's go, let's make this one, this program, practice program is a PPU and SPU program, okay, and tell me how to do this one, all right, so let me have this one program, bring it back, T1.C, okay, what portion we want to make an SPU and what we want to make a PPU, okay, let's do this one, okay, let's say that this one over here, we will make it as is what, we save these programs, we will make this loop here, these operations as a SPU program, okay, so we save this one, write this one as is T1 underscore PPU.C, and then we figure it out, right, and then we write another lazy one, write one as T1 underscore SPU.C, so we save it sometimes, okay, right, so now we go back in here, we say that we have an SPU program, this is our SPU program, and now remember float A and B and C, we just bring it down there, right, so we have an application, an SPU application with its own data, right, to keep the data down in the SPU, okay, it's fine, okay, man here, the same thing, insert arguments, this is an SPU program, right, three arguments that we need to have, number one is, all right, unsigned, long, long, right, unsigned, unsigned, long, long, SP, SPE, what, ID, right, we need to have an SPID, because this is an SPU program, unsigned, long, long again, of what, argument point ARG, right, and unsigned, long, long, environment point ENVP, whatever, right, okay, and okay, so we have this, we have an ABC, do we need to do anything here, the data is still here, I bring the data to float ABC down to here, okay, so we finish, right, make sure that I do the correct programming here, all right, so we write and quit, okay, VI, the, our PPU, T1, underscore PPU.C, correct, all right, now I have the data down in my SPU, so I just go ahead and delete these guys, right, okay, delete these guys, okay, this look, or this operation here is now belong to the SPU, so I command this out, right, I insert this one, command this one out, and I need to return this one, all right, so this is my SPU PPU code, first thing what I need to do, I need to create an SPE thread, right, SPE create thread, correct, right, and I give what, what is thread, T-A-D, hammer, all right, and then what, the first argument is what, my group ID, right, I put it 0, so this is my, my what, my group ID, group, SPE group ID, right, SPE group ID, okay, the next one would be what, what's the next argument here, my, my program handler, right, this is the pointer to my program handler, which is T1 underscore SPU, right, command this is my program handler, okay, and go down to third argument is what, my pointer, right, which is my known node over here, I just put known here because I will set it, all right, this one is, is my argument pointer, our pointer, pointer here, and then to third one is known, okay, and then this is environment pointer, ENVP, ENVP pointer, right, and then I have a, and then, sorry, and then what they have, we have a mass ID, all right, okay, minus one, when we use minus one because it's not working fine, you know, as of now, any, okay, this is my, my, my, my, my SPE, SPE affinity, right, need T, and then we have a zero with a flux, right, that's 40, 30, right, okay, flux, right, the flux one for my, okay, and then what, then I have to wait for, right, I always have SPE, wait, okay, SPE, wait for my, for my SPE, SPE ID, ha, right, SPE ID, status, and zero, now, so now, we're going back up, right, this, this code, right, we return what, voila, yes, in SPE ID return to, right, SPE ID, not too fast, right, now, SPE ID, so we have this one, so we have to declare SPE ID somewhere, correct, and okay, SPE ID underscore T, right, SPE ID underscore T, what, it's my SPE ID, SPE ID, right, status, I declare over here as well, so I have to int status, right, okay, now, in this program, I use what, T1 underscore SPU, which is my program, I have to go back up here, I have to declare some things up here, right, before this domain, right, external, external what, external of SPE underscore program handler, handler underscore T, right, and then the name of the program is T1 underscore SPU, that's it, so that's my SPE program, correct, all right, what a grid, right, and my Mac file, my, my SPU Mac file, what is, what look like my SPU Mac file, VI, that's for example, right, this because I would have the directory, okay, so now, we have the PPU program, the SPU program, correct, we need to do the Mac file, the Mac file is on the PPU straightforward, right, we specify what, okay, let's do it, this is the Mac file for the PPU, okay, I'm just make it up, so here we go, this is the, well, this is already made, this is the Mac file for the, for the SPU, right, we don't have any things here, and okay, let's say that, let's assume that this one is the Mac file for the PPU, right, program underscore PPU here, right, and the T1 PPU, correct, and then what, we have to import, very good, import or RTS, import what, import the, we assume that T1, T1 underscore SPU dot A, the files, right there, okay, and then the last one, now let's if this one is an SPU Mac file, okay, this is SPU Mac file, okay, so the program is the SPU, correct, all right, and then over here we do what, we say that we do the library, right, we specify a library embedded, all right, library underscore embed, equal to what, what we embed in here, we embed under, let's say that this is the SPU program under the SPU directory, correct, right, and we embed, so we have to go back to the PPU program, edit the directory nearest equal to SPU, so we do the SPU, details, you know, okay, SPU T1 underscore SPU dot A, right, and then LSPE, correct, okay, so what happened here, what I have shown you is that a typical, these are on the, on the PPU programs, one thing's missing, what do I miss here, include, plus include what, include what, live SPU dot H, right, this is needed because I do the thread creations, if I, if I don't do anything, you know, I don't need this guys, right, okay, so, all right, so we, we have the T1 dot C program, fine, so far so good, all right, let's take a look at T dot C program, same program, all right, now we float, we make an array, three arrays, 1,000, 1,000, 1,000, and the main is, you know, now we do a loop, we do for the loop count and we do loop, right, so far we're okay, all right, okay, we, let me go back to here, and then the day three same trace and I will go to what I have in here and I'll show you, what I have in here is have a directory of seven different test cases, all right, I have the one PPU only, one is self-DMA with one SPU, we do the transferring here, okay, and then we do another DMA transfer example here, and we do the DMA list transfer, we do the multi-SPU, we split the task into different SPU, and we do the multi-buffering, and we do the software cache, the software cache I mentioned yesterday, but they did not have the time to go through, I forgive me because that I want to bring you up to speed so that we wrap it up, remind you what we've been through, and now let's take a real, some real examples, and this example here, this is the h-file, okay, use the text part because this is quicker than going to do this, this h-file, what do we have in here, this is an open source version, so it's going to help, I don't have anything, okay, so I'm going to bring it up, this is my PPU programs, okay, bear with me, I will walk through a little bit slowly here, but then I move it on quite a fast, right, standard IOH, we don't, is it clear enough for all of you in the back, it's okay, so what we have in here, we define an array size of 1024, and a number 512, and I use this one so I can define the alignment of array A, array B, and array C, okay, so a little bit changing, but here nothing else, we say that my align here, give it my var, def define it, and my my array, my alignments here, and then we define the attribute would be for this one, so I use this one here to define the my align of array A, array B, array C, it's nothing else, but to define array A is an array of 1024, alignment of 128 bytes, align of 1028 bytes, align 1208 bytes, so what I'm going to do here is to add the two elements together, all right, and put in C and A and B, whatever, okay, so this is a routine I use to initialize an array, nothing else, right, I put an array here, I call it init array, and I have an array 8 sub i here, go to all the i elements, i times num, i times num, times two, and so on, clear, so far we okay, nothing, no, we haven't done anything yet, let's look at the main program here, there's some tricks, some techniques that I would like to share with you, that's up to you to use it or not, okay, in here, we do the integer array, right, we do an add array, array C, A plus B, that's it, instead of two numbers now, I have an array, okay, C equal to A plus B, and a print out array, very fine, some number, that's my PPU program, so far you with me, okay, well PPU program, standard, right, we haven't called anything, we haven't split it yet, right, okay, already you will see, okay, so we have that, and then PPU only programs, that's the only thing we have, let's take a look at these guys, all right, in the step one, array of H, okay, what I'm doing here is that I define a structure here, I call it control block, right, I have in A, I have A, B, and C, okay, and I also have size, so each of the elements here is what, four bytes, four bytes, four bytes, four bytes, okay, we align this structure here to 128 bytes, so I have to pass it here, right, I have to pass that address, so I have 128 bytes, okay, so that's my control blocks, all right, we finish that one, we take a look at the step one, step one corresponding to the programs that has not simdised yet, and step two is the simdised version of the program, okay, so you have a scalar version and a simdised version, what you can look at, you know, when you get the times, this afternoon or if not, I give you this one, you can look at, you know, by the times you will hold my sword, let's look at the SPU program, all right, I bring up this one, using my text path, okay, this is my, all right, I will get out this one, I would like to bring up the SPU program as well, right, so I can put side by side and we go over, so what's going on, right, so I did that and then on the window, I put them, I tie them vertically, right, okay, so this is what, this is my SPU program, okay, what I'm going to do is that, in this program here, this is my PPU program, on my left side is my PPU program, the right side is the SPU program, correct, all right, so on my PPU program, I'm going ahead and I locate it, define it, my alignment of my array here, ABC, correct, and then initialize it here, didn't change anything, nothing, okay, then I initialize, the main program initialize array and we create an SPU thread, okay, and create an SPU thread to process the array SPU, okay, I create an SPU here, an array, create a thread and in this example, I will send the address now to the mailbox which I really don't want to show you yet, but you know just go ahead and show you here, I will send effective address to the SPU now to the mailbox, okay, I create an SPU thread and this is my SPU program, nothing, I send it out, right, I will use the mailbox to send it in address now, the mailbox is used for message, sending message, all right, in this case, instead of sending message, I will send it in address now, I will use the SPU ID here, which the SPU ID that I just created, okay, and I send the address of the array A, it put in that mailbox, this is the address of what, of the array A and this is the address of array B, okay, and also this is the address of array C, why I want to do that, why I want to do that, I can either send my address now when I create the thread, I have a three arrays, so I have to do the same thing for three times, right, or I can send the address of the control blocks and let the control block contain the address of my array A and B and C, or I can do this one as well, that's why I want to show you the two different techniques, this is the first technique, using the mailbox to send it down to the address of an array, all right, so we do that one, we have the address, by the end of this one, I send it down to the SPE three address of the array, okay, so now on the SPE programs, on the, I have the control blocks declared here, that's my local, okay, somewhere, okay, right here, the alignment control block, this control block is local CB, local to my SPE programs, I still declare the array A and B and C right here, I get the control, with the argument pointer from these programs, I get the address, the effective address from the AARPGP here, and then the size of the control blocks, okay, and the tag here 31, so I get that, I get that address for, I get the address of the control block now, so by using now the MSC gate, where I have to have the address of the A here and B on the local now, and the components is the A components address of the array A and address of the array B here, I download it out to my local areas here, and then perform the calculations, I perform the calculations just right here, okay, same things, A, B, C, C equal to A plus B whatever, when finished, I send it back, MSC put here, array dot C, array underscore C is the local array, the effective address is CB, in my control blocks, and then the size and so on, I send it back, we so what we did was that what we had before was that we have in the additional operations on the PPU, right, and now we shift it down to the PPU, right, so we everything that now instead of having the data now into the PPU, we said we keep the data somewhere in the effective address, right, and when we send the control block now so we can identify or we can acquire the address of the array A and B and C, and then we use that one, demate the data now, okay, control block, techniques, right, no mailbox, nothing, we have a control block we defined before under array underscore h, underscore add dot h here, that heading file, we have, we declare the array here, the size, array size, alignment 128 bit 128 byte alignments, we have a function here to do the initialize array in a main program, look at the main program, we initialize an array, okay, and then we check the number of SP working, you know, this is an extra, extra nears, if you want to be really careful when you do that, all is the same, right, and now here it is, I think it's much better, it's much clearer for you, this is the CB dot A, this is a CB dot B and CD dot C, the C of, we get the address of array A, beginning the first locations, right, and we give it to a CB dot A, refer to CB dot A, and we get the address of array B, okay, and send it, this is B components, okay, and address of C, and then the size, it's this size, okay, we clear this structure here, and then we create an SPA thread, again the same thing group ID, the name of the program, and here, here's what we send it out, we send a control block now, okay, so what we actually we send a structure now, which contains address of A, address of B, address of C, and each of these guys is thousand, do we care about breaking up, how we don't care yet, right, we, and so we go into print, after that we print and so on, we don't care this one, and here we synchronize, right, a lot of time we talk about, you know, once we, how do we know, then when we, when we know that we finish transferring the data, and how we sync the address between the local store and FET address, this is the typical instruction we use to sync between the two of them, okay, we do that one, and we wait for the SPC. Okay, so this is the SPU program, on the SPU programs, I define everything the same, like we before, these are right here, control blocks, this is my local control block CB over here, and then the first one would be, you know, to get the, I only have the control block passing down for me in this argument here, right, so I go ahead and use that argument and get the data of the size of the control blocks, bring it down, and then now I have the control block down on my SPU, or now, all right, so I use that one now, they refer to the components A, use that one to refer to my effective address, and use the CB, and then do the two MFC gates, right, one to get the A, one to get the B, and then the right tag mask, and so on, and the size already specified by the size that I have when I bring it down into argument pointer here, passing to me when I create a thread, I do the matrix add, and I put the bug, I put the bug seed here, CBC, so what we did was that we have a control block down, you know, somewhere, define it that containing some address of an array A and B and C in the size and so on, and we pass on the, on the PPU, we use that one to load the data, and then on the SPU, we pass that control block, the address of that control block down to the SPU, so we can refer to the element within that control block, that's it, right, and then we use that one to, as an effective address, so we can download, you know, the data to array A, data to array B, so we can perform this operation here, and we use the same strategy again, send it back to the, to the, to the, to the PPU program. That's how we pack up the data, and then how do we change. This is the SPU versions of the programs, of the SPU program we just mentioned about, and for, however, this is the, the vector versions, right, and here I do the same things, my, my define my alignment is still the same, and my arrays, I declare the array now instead of the full array size 1024 or something like that, I divide it by four, right, because and now I declare this one as a vector, my array A contains, contains a vector, it's a vector of elements, it's a vector of array B and a vector of array C, control block the same, okay, I do the same thing, see, I form, this is a SPU program, I get the control blocks from my argument list over here, check the tagmas, starters, whatever, I get the array, we do the same thing, do the same thing, do the same things, nothing changed in terms of data transferring, get and put, do the same thing, right, through the control block, okay, the actual operations now instead of array, up sub i equal to array A plus array B, okay, we have a SPU add, I have to use intrinsics functions to add this guys, we get four statement over here because of what, because of what we're doing here, un-drawn the loop, un-drawn the loops right here, right, so we, we, we not only vectorize this one but un-drawn to, to make some optimization as well, so that we're going to we speed up, we, you can leave it here if arrays are four or whatever, just doing one at a time, pardon me, right, yeah, we'll, four elements right here, the, the story here is that once you, yeah, the vectorized versions is, you know, you have to take care of your, your data here, it's now instead of single elements, it's not a four elements per, per instructions or per array, and then you do have with the, the, the calculation that you need to take care of, memory transfer remain the same, nothing change, so you deal with data on it. Is it possible to get a single variable out of a vector? Sing element with extract, right, right, okay, so we finish that one, let's take a look of the DMA list, okay, this is my, the array H I think will be the same, I didn't change anything, the control block, okay, this control block remain the same, right, and now we add the structure here. Remember this, the element of the list is an 8 byte, all right, and then we have the first bit whatever, we have the, the, the store bit, and then we have some the bit reserve here, and the number of bytes transferred is 16, so this determines the bit structures here, and then the size of this one is the, the unions of this unsigned int own 32, and then, and then this structure here, so we have, we define this one is the unsigned int below, all right, I step one on my PPU program, what I'm doing in my PPU program, in my PPU program, I still floating, declare my array here, my control blocks the same, my control blocks now contains A, B, C, the array, and then the size and so on, so I have this one the same, nothing change, I'm go down here, I check for the working hardware, nothing change here, my control blocks get the data from my control block, I set A and B and C, and it creates the threads, okay, the PPU program, we pass the control block down, and we do, we wait for SP finish, it will change anything, nothing, all right, okay, so far so good, we just go over here, and we pick up the SPU program, no, no, wrong one, right here, right, the DMA list, this is my SPU program, my array the same, nothing change here, my DMA list now, I have this structure, we call the DMA list elements, we call that list, we have a 16 elements, so we, 16, let's mean what, we have a 16 command, right, a list of 16 DMA commands, okay, why the 16 DMA commands, because how many, how many bytes we transferred out every time, maximum is what, 2K, we will see, right, okay, align A byte, right, DMA control blocks into local store, we get that DMA control blocks, so we have everything down to the local store now, next, we, okay, we do have a, what we call the transfer the large regions, okay, and now we have a two, two routines here, right, we have a one is transfer the large region where we go ahead, we, we call this routine here, transfer large regions, we give it address of array A, we say that, okay, now transfer the address of the, go ahead and get this effective address here, that's I passing by my, in my control blocks, okay, and, and local is the array A over here, and this is the size, how much, how many that you translate going down, and one, I think that's some of the flux that I set out here, okay, this is my transfer the large region, let me go through here, there's been, you know, couple of weeks I've worked on this one, so unsigned, tag ID, the list size, if the number buys, not equal to zero, whatever, it will return, okay, greater than zero, unsigned the size over here, what I'm trying to do, the same thing like the, how much I explained, I'm working through the list, okay, and I say that, you know, I have a, if I answer the size, if I have a greater than 16k, right, the size over here is n byte, it's less than 16, 384, or n bytes, otherwise n byte is 16k, so I move 16k at a time, and then down over here, list of i, the size 032, I put the size in there, and then my effective address is low, I put it in here, and then increase the size, I reduce the size of the buffer, of my main buffer there, of the arrays that I have, and then increase that size, how many more bytes do I transfer, and I go back to this loop, so what I'm trying to do in here is that I transfer 16k at a time, and I use the EA law to identify my, to move my pointers right next, and move this one 16k, and the next 16k, next 16k, okay, and then the list size here, we take up the size of the DMA list elements, okay, so I have that, now I have all this learned now for me, now I do the actual work, right, now if I pass to either 1 or 1 or 0 here, right, if it's 1, if it's get here, as I define, get somewhere, either 1 or 0, and I, you know, depending on the condition that I, the flux I set there, I can do the get list, put list, right, if the get list, I have the local address right here, and the list elements start by the first elements, and give it the effective address load over here, and then the size, the list size, and the name of the list, they are the first location of the DMA list, and either put, put out, and this is going to respond the same, exactly, you see that all of these instructions, MFC get, MFC put out, basically the document list, the same document list, right, so either we use, we specify the local stored address, the effective address here, and then the list address, right, so and then we let it go, do we care about it how often, and when we finish it, not know, right, we just use this subroutine here, okay, to get the data and supplied right here, we move this, how we use the move the data to array A, move the data to array B, and then so we perform this function here, and then we transfer it back, and we use this flux here to say that this is my put out, so we use the put out to get out and the put out to get the data is in the list, so we don't have to worry about, you know, just individually, so that's the different techniques we use. We have seen both the examples doing exactly the same thing, okay, so in this, even in this list example, since you are putting it into already defined arrays, you are not exceeding 256k at all, okay, so the question of 16k into 2k doesn't arise, because you will never exceed that, you are putting it into this particular array, all right, so what is the advantage of a get list over a single call which gets me the full array, okay, so if I have got single data which is more than 16k data transfer, then I can use list, I had a different question in mind, okay, basically the list does it in chunks, okay, so even if the list is not over, I can actually start processing the first chunk, is that the advantage, but then there is no mechanism for me to know which chunk has finished, no, is there any way of knowing that, is there a way of knowing like see when I do a MFC get, I do check for the status, it is over, inside the program, can I find out that what is the status, first list item is over, second is over, third is over, no, but there was a tag bit, each list element has got a tag bit, each list element had a tag bit, each list element, the 8 byte element has got a tag bit, same tag bit, it is all under the one category, the whole list, so I thought that was used for completion or non completion, no, as for one, one whole list has worked out, one later time, okay, this is an example of double buffering on the PPU program, PPU program the same, nothing changed, right, straightforward, and then initialize array, the programmer here, this is the SPU, and okay, check for the working hardware, and then I do the, here I didn't find the buffer here, okay, I have the array size times I divided by 8, is the offset into my array, and then this is the 63, 64 to 464 byte here, 40 offset sub-ites, increase that one, and then start arraying the cache line, get the control blocks, going down, okay, let me do this, let me go and get the SPU program, SPU is better, T-prex, five minutes, and then I take offline some questions, okay, come, yeah, okay, let me bring up the SPU program as well.


Can the guys at the back hear me? OK? OK. So my name is Hybin. And I would like to give you an introduction to functional programming in Python. Can the guys at the back see the screen? Maybe a little bit small if you want. You can just come to the front. So just a quick remark that the techniques that I'll be showing in this talk comes from a different language called F-Sharp. F-Sharp is a functional first programming language developed by Microsoft. So the language design of this F-Sharp comes from a lot of different languages, like Haskell and also from OCaml. It also gains a lot of influence from Python as well. So Python has a lot of good language design that influence F-Sharp. And I want to bring it back from F-Sharp back to Python and show it to you guys. So my name is Hybin. And I'm currently a data engineer. I have a master's degree in mathematics. I used to be a financial engineer and a business analyst somewhere else. So today, I would like to illustrate three concepts in functional programming. And I want to show you the style of writing code in a functional way, in an F-Sharp way. The three concepts are keep, change, and then. Keep, change, and then. If you use a more functional language, you may see jargon like filter, map, and pipe forward. I keep it simple. Keep, change, and then. There's also another keyword called reduce. I'll briefly mention about it later. So let's start off with the keep function. Let's say that you have a list of 1 to 10. You want to keep the even numbers. And you want to remove odd numbers. What will be your final result? Your result will be 2, 4, 6, 8, 10. So far, so good, right? Nothing fancy here. Still easy. If let's say you have 1 to 10, you want to keep the prime numbers. What will be your final result? Your result will be 2, 3, 5, 7. So given a list and a condition or criteria, you can create a shorter list such that you keep those that are true and you remove those that are false. Granted, in Python, you can already do this in pandas. You can already do this using list comprehension. So you can already do it in Python. So I just want to highlight to you the existence of this thing. And I'll combine it with the other concepts in order to solve problems later. You can also define the remove function that does the exact opposite of the keep function. So far, so good. Now, the change function. From 1 to 10, you want to change x to x times x, change x to its square. What will be the result? The result will be 1, 4, 9, 16, 25, et cetera, et cetera. Straight forward, right? If let's say you have 1 to 10 and you want to change it to x to 1 divided by x, what would be your result? Change x to 1 divided by x. You'll get 1 divided by 1, 1 divided by 2, 1 divided by 3. You get all these fractions. You can also express it in decimals if you want to. So again, given a list and a formula of how you change each individual element, we are able to create a new list that depends on the original list and the formula that you want to transform each element to. Again, you can already do this in pandas. You can already do this using list comprehension in Python. So again, I'm just highlighting these concepts to you. These concepts should be easy. But I want to highlight the next concept later, but let me do a summary. Why do we want to define these functions, the keep function and the change function? It's because it allows you to avoid using for loop, or at least you can use for loop implicitly in your code. You just tell the computer, what do you want to do with the list? Do you want to change it? Do you want to keep some element or remove some element? Usually when you have a list, you either change individual element or you keep or remove some elements. You are able to work at a much higher level, and you let the computer handle the details at the background. Just tell the computer what to do, how to do it, but you don't need to implement the for loop yourself. So these are all good. You can already do this with existing Python code. But I want to highlight this one. This is the key concept for today, which is the then. Let me do an explanation. Can you guys see the picture over here? The picture over here? I start off with an element x on the left-hand side, and I want to pass through three different machines, three different functions, F, G, and H, in order to produce the final result. I have an input x. I want to go through three machines, three functions, to produce the final result. How would you write this in mathematics or in Python? You will write something like this, HGF of x. Is this OK? Yeah. So this is all good for programmers and mathematics students, but it's not so natural to, let's say, a typical English speaker. Like this notation looks a little bit scary for non-programmers or non-mathematics students. It would be great if we can write it in such a form. You start off with x, first you do F, then you do G, then you do H. This looks a little bit easier, right? It takes up more lines, sure, but this is a much easier formula for, let's say, a non-programmer, let's say, a typical English speaker. It's like following, let's say, a cooking recipe, like step one, do this, step two, do this, step three, do this. And by hacking around with some of their Python syntax, I'm able to achieve this. It will look something like this. Something like this, this would be a valid Python code. First step one, you do F, step two, you do G, step three, you do H. The actual definition of the then function looks a little bit complicated. You don't need to remember it, but the quick key concept is this. I can express my calculation using a step by step, like step one, step two, step three, like this. Is everything okay? Now with these three concepts, keep change, and then I'll start attacking some problems from Project Euler. Have you guys heard of this website called Project Euler? Maybe some of you have. Have you guys heard of this website called Hacker Rank, or let's say some of those challenge programming websites, where you can try out some programming challenge problems? So this is Project Euler. It's one website with math and programming challenge problems. And I'll attack problems from this website using the techniques that I mentioned just now. For example, question one from that website. From 1 to 999, find the sum of all numbers that are either multiples of three or multiples of five. If let's say you are faced with this problem, how would you write a code to solve this problem? You can certainly use for loop. You can certainly use list comprehension. If you want to be fancy, you can use pandas. But let me show you my way of writing it. I try to import the techniques from the language F sharp. My code would look something like this. This is my code. I'll leave it from here for a few seconds. The key benefit of this code over here is that you can see a line by line translation with the English language. So on top is the actual Python code. Below is the English translation. I start off with this list. I keep the numbers that I want. And then I sum it up. And then I print out the results. Let me do a step-by-step illustration. This is the first line. I have the range of numbers. And then I keep the numbers that I want, which is divisible by 3 or divisible by 5. And then I sum them up. And then I add one more instruction, which is print out the result to the console, which is the Python print. Notice that I break up this question into a step-by-step instruction, like a cooking recipe. Like step one, do this. Using the result from step one, do the second step. Using the result from the second step, do the third step. Any questions? What's the speed of these methods compared to the Python? OK, I'll explain about this later. There are some pros and cons about functional programming. I'll explain with another example later that functional programming, there are some bad parts in the sense that it may not be the most efficient method, if, let's say, compared to, let's say, using index or like going through it, like for i in this range, you do something, something. I'll show with another example later. Sometime it's not as efficient as the best method, but what you get in return is extremely clear clarity. You are able to see the step-by-step process of what's going on. I'll show you with a not so efficient example to see the bad parts about functional programming later or rather like criticism. So for example, question number two, in this list of Fibonacci numbers, in this list of numbers, what is the sum of the even numbers less than 4 million in this list of numbers? You have a list of numbers. What is the sum of the even numbers less than 4 million? My solution, again, you can do it in pandas. You can do it in list comprehension. My solution would look like this. You need to do some construction of the original list first. And then afterwards, you can just do this step-by-step process. I'll do a step-by-step demonstration. You start off with the original list. This is the original list. You keep some of those that you want. Then maybe I'm not satisfied. Maybe I want to keep even more stuff. I want to remove even more elements away and keep those that I want. I keep those that are less than 4 million. I keep those that are divisible by 2. I sum them up, and then I print. Notice that it's step 1, step 2, step 3, step 4. Any questions? Yes, I can actually run that. Let me run that after a few more examples. So for example, question number 4. A palindromic number is a number that is the same if you read it from left to right and right to left. A palindromic number is, you can sort of think of it as a mirror image of itself. You read from left to right, right to left is the same. The original question asks, which three-digit number, A and B, which three-digit numbers, A and B, will give you the largest product C, and C is a palindrome itself. A and B do not need to be palindrome, but C needs to be a palindrome. So again, the question asks, what is the two numbers A and B that produce the largest C such that C itself is a palindrome? If let's say you are faced with this problem, how would you solve it? How I would solve it would look something like this. I start off with each pair of numbers, and then I calculate the product for each pair of numbers. And then I keep those that are palindrome. And then I find the maximum. And then I print it out. There might be some slight modification you need to make in order to make this function work for tuples. But roughly speaking, this would be how it would look like. There are some modifications needed to make it work for Python syntax. Is it OK? So for example, question number six, they ask you to calculate this, like 1 plus or this sum squared minus that calculation. So one benefit of this notation is the following. So you have 1 to 101. You have 1 to 101. I add them up. And maybe I'm not done with my calculation. I want to take this sum and want to square this whole expression. In let's say list comprehension or let's say in pandas, once you get away from a list or once you get away from a pandas, you might not be able to use pandas, those apply or filter to continue your calculation. Over here, I have a list of numbers. After I add them up, I immediately take that sum and immediately square it. So my calculation do not have to stop. I just keep on adding one instruction, adding one instruction. And similarly, I can calculate whatever's on the right-hand side using the same notation. And then I take left-hand side minus right-hand side. That's my final result. Let me stop for a moment. And let me show you the actual code, OK? So apart from some helper functions, notice I tried to solve the first 10 problem from Project Oiler from this website using only the then notation. You can notice that over in my code I use then, then, then. Let me scroll down, question 1, question 2. Question 2, like you see then, then, then. Question 3, then, then, then. Question 4, then, then, then. Let me run this code. And it will produce all the results for question 1, question 2, question 3, question 4. Which means that whatever my code here, it compiles. It actually calculates the right thing. Question 10 is going to be a little bit tougher because this method may not be the most efficient method. But at least it's still doable if I force myself to use the then notation. I do sacrifice performance quite a bit in some certain situation. But what I do get back is extreme clarity of what I'm doing with my code. So there are some pros and cons. If you are doing high performance, like computing or maybe low latency stuff, this may not be the right approach. But if you are doing something very low latency, most likely you'll end up in C++ anyway. But if, let's say, you want to do general programming and you want your code to look really nice and really understandable, this could be a good choice. And another benefit is the following. So take a look at this code. Take a look at this code. The difference between these four statements is that I add an additional line after it. So x1, x2, x3, x4, they differ only by one line. And notice that all of them compile and all of them do print out something. So what this means in the development process is that I don't need to set up a really big for loop, a really big pandas process in order to see the result. I mean, pandas actually does something similar, which is the step-by-step process. So you don't need to set up a really huge for loop. You can just add one more instruction and immediately see the result. It will compile. It may not be the final answer that you want, but you can see the result first and then continue with one more instruction, add one more instruction. So at any time of the process, you can stop and immediately see what's your result. And if you are not satisfied, add one more instruction. That also helps in the development process. Question number eight, which is an example that I want to get to, which is the criticism. So you have a really long string of digits. You have a really long string of digits. And you take four digits at a time, four digits at a time, four digits at a time. You calculate the product. The four largest digits that produce the largest product is this 9, 9, 8, 9. So in this long list of the string, this long string, the four neighboring digits that produce the largest product is 9, 9, 8, 9. In the original question, they give you a 1,000 digit number. They ask you to calculate which 13 adjacent digits gives you the largest product. In the original question, you have a 1,000 digit number. And you calculate which 13 digits gives you the largest product. So you can try to approach this problem using a more traditional like for loop or pandas or maybe list comprehension. My solution would look like this. This would be my solution to this problem. Let me do a step-by-step analysis of this problem. I have a long string of numbers and I take out each individual character and I convert it to an integer. This is step one. And step two, I break it up into windows of 13. So over here, I have a list of 13 numbers. I have a list of 13 numbers. I have a list of 13 numbers. So I have a list of lists. I break it up into windows of 13 and each window, I calculate the product. And after calculating the product, I find the maximum and I print it out. This would be my solution. There is one criticism to this problem is the following. At this step, we have 1,000 digits. This step, we have 1,000 digits. The next step, I break it up into windows of 13. What this effectively create is approximately 1,000 such windows. Each window has 30 numbers. So effectively, I take a 1,000 digit problem and I convert it into a 13,000 digit problem. Is it the most efficient? Most likely not. Because I take 1,000 digit and I create approximately 13,000 digits before I do any other computation. If you are resource crunch, if you don't have enough resource, then this may not be the right approach. But if you have the resource, this gives you the benefit of extremely clear code. You are able to see each step of the process. What am I trying to produce before I hit the final result? Is this okay? So there's more math examples, find A, B, C that satisfy these conditions like satisfy A square plus B square equal to C square. So my code would look like this. Each pair of A, B, I calculate the value of C and then I keep those that satisfy those conditions that I want before I print out the final result. Some modifications are needed in order to make it work for tuples, but approximately it would look like this. So it's all fun and games like playing with mathematics examples. Let me try out like a non-math example. So take a look at this code. It looks like I try to squeeze a lot on this page. This is like some sample code, like non-math example. Let me try to go through this code step by step. I start off with a SQL query over here. I start off with a SQL query over here. And I format this YY MMDD over here. I format this YY MMDD with today's date. So this is what I have at the bottom. I format the date into that SQL query. And then I run this SQL query to a database to produce some results. Then I get a list of results. Maybe I can do some data cleaning. Maybe I change the country so that it's in capital case instead of lower case. I change, do some data cleaning. And then I do some data filtering. I want to keep the sales that are in Singapore. I do some data filtering. I keep the stuff that I want.  Then I get a number. Maybe I'm not satisfied. Maybe I have a number. I want to go one more step. I want to calculate what's the 20% of my commission. So with a number, I immediately multiply it by 0.2. So this would be a valid calculation using the den notation. Everything okay? Maybe let's try another non-mathematics example. So over here, in step one over here, I have a local folder in my computer. I have a local folder. I list out where the content of that folder. Maybe I do some data cleaning. There are some corrupted file in that folder that I do not want. So I remove them. Maybe they are corrupted files. I remove them. And for all the remaining good files, I count how many lines are there in those files and I add them up. I sum. This would be a valid code using the den notation as well. So I don't have a database. So I'm just like creating some dummy data that immediately runs. So just to show you that the first example, the first non-math example, it actually works. So it doesn't give me a compilation error. It gives me a result, which means that it works. And also similarly, let's hope it doesn't crash. Yep, it works, yay. So I go through my list of the content of my folder and then I do some counting, do some data filtering. This also works using the den notation. So that's roughly it. Let me do a little bit of extra about functional programming. There's also the optional topic about reduce. Take a look at this code over here. You start with zero, from x from one to five, you add to the starting result and you print out your result. From zero, you add one, two, three, four, five and then you print. You get the answer of 15. If you change your starting value at the start, which is, I change it from zero to 1000, I start off with 1000, then I add one, two, three, four, five. My final result will change. That's easy, right? If I change my range of value instead of one to five, I change it to one to 15, then my final sum will also increase as well. If I change my formula, instead of adding numbers, I multiply the numbers, I will also get a different result. So with a starting value and a list of elements and how the formula that you want to update your starting value, based on these three conditions, you can calculate the final value after you accumulate truth your whole list. So this thing that we usually call reduce or fold, this thing we call reduce when combined with the keep function, combined with the change function and combined with the then, we will be able to allow you to tackle even more problems. And the final finale is the infix operator. I want to highlight that this very simple math expression, three plus four, what does this mean? Three plus four, what I want to focus your attention on the plus symbol. The plus symbol connects the left-hand side and connects the right-hand side. It connects the number on the left and number on the right and it combines a final result. What the symbol does, it takes the number at the left and number at the right and it combines a final result. If I change it to multiply, three times four is 12. The multiply symbol also takes the left number and takes the right number and combines and gives you a final result. The key concept here is the then notation takes the left expression and the right expression and gives you a final result. The then notation takes the left expression and the right expression and gives you a final result, which if you write it in multi-lines, if you write it in multi-lines, it takes the top expression and the bottom expression and gives you a final result. That's the glue that glue everything together. And so just a summary, we have gone through key function, change function. You can already do it in Python using this comprehension pandas, but what's important here is the then notation that really glues everything together and allows you to write really clean code. May not be the most efficient, but certainly very clean and understandable. And with that, that's the end of my talk. Yes? Do you think that the way you present it here, Yes? Why do you define this for a need to be taught? This course, the answer beginning before you start to optimize the code, you need to understand how you write your code. So functional thing, do you think it should be a foundation and then optimization first or different ideas? It really depends on the, it really depends on the feel, I guess. If let's say you want to do extreme optimization, let's say high frequency trading, or let's say something really fast or low latency, this is not the right approach because you'll take up a lot of overhead and also you may not be doing the most efficient optimized method. But if you are working on a much more higher level, or if let's say you want to write code that your colleague can understand, your coworker can understand, for more practical reasons, this might be a slightly better way because there are other aspects of functional programming like mutability and also other stuff that are also important to help you write clean and understandable code. If the computer is able to understand what I've written just now, you don't need to go to a much lower level which is let's say a for loop unless absolutely necessary because if you are using a for loop, we need to go through the index, you might potentially get let's say a list overflow, let's say a list has 100 elements and you access the 200 element from that list and then you get like some error. Using for loops and other things could potentially cause to error which like my style of writing does mitigate some of those risks as well. The example you pointed out about the file directory, say for instance you have some background and you want to remove it. It's illustrated by you just now. Yes. So I quite disagree with this thing. Yes. The point is, it seems to me this is totally case insensitive. So I don't know what are the underlying code because literals can be changed to hexadecimal or decimal or whatever that is which represent that and in such a case, it's actually case insensitive especially in the unique system which you can use question mark as a file name which is unseen in Microsoft stuff. Yes. So that eliminates a lot of capabilities and this won't work anyway. For that, because I'm only doing some like basic examples, if you move, there are certainly some higher level functional programming concepts especially if you are using Haskell where they enforce purity a lot. What purity means is that, for example, let's say you want to talk to a web server or let's say you want to access a database or let's say you want to read a file code, you want to read a file from your computer. All of those process could potentially fail. You get something from the website, you get something from a database, you read a text file from your computer, all of those will fail. At this current level of functional programming, only change, keep, and then you are, it's somewhat limited to attack those higher level problem which is handling potential failures which some other functional languages like Haskell handles it really well. But yeah, I understand your consideration. More questions? This is a bit related. This is a fascinating way of writing functional programming but it goes really clean. I'm curious about error handling in general. You're doing this in Python. What has been your experience? Is it putting a try accept amount if the accept is going to be hideous? Effectively, you can certainly create like let's say a data type. Let me write it here. Let X equal to one, two, three, true. So let's say X is a variable that contains two content, a number and a true false value. So if let's say the second value is true, I can safely act on whatever's on the left-hand side. And if it is a false, then I have no guarantee what's on the left-hand side. Maybe it's a decimal, maybe it's a string, maybe it's null. So like such a simple data type which is a tuple, you store whatever information you want on the left and you store the true false value on the right-hand side and that will give you an additional guarantee. Not 100% in Python, but the guarantee is much stronger in other functional languages like F-sharp and Haskell. Okay, sorry, I messed it up a little bit different. So if you've got a list of these tuples and you have to first index one of them in a lemma function and it's not a list, that's just going to throw an index error value error. You hash that and deal with it, right? But the code looks fantastic, I guess. I would say that like it's, you know, so suddenly like because Python is dynamically typed, so there's only limited capabilities of, you know, what we can guarantee to it. So if you are using like let's say F-sharp or Haskell, they also have static checking which checks, you know, whether something is, you know, exists or not, then it will help you detect whether something is not. Maybe if you want, we can talk about it after the talk. Okay, one more question. Thank you for sharing. I think it's really interesting and I've done some programs by myself. Yes. The code becomes so long. So anyways, my question is, how do you measure the complexity of a functional programming code? Measure the complexity of functional programming code.  So let's say like an example like this, I started with a list and then I do some keeping or removing. I remove the stuff that I do not want and I keep the stuff that I want. Then I do another step. I keep the stuff that I want. The problem here is that every single step, I have no guarantee if anything will be removed or anything will be keep. The worst case scenario is that every single step, I keep everything. I cannot remove everything. So I started with a list. I keep some stuff and then I keep some stuff. There are no guarantees of removing stuff. The worst case scenario is at each individual step, we are recreating the same list again. So when you write code like this, you have to keep this at the back of your head, I guess. If let's say you are doing calculation on let's say a list of billion stuff, then it might not be the best way. But generally speaking, if let's say your list is less than one million or maybe 10 million, this should be okay. Less than one million, then this method usually is okay. Of course, it depends on your data type, I guess. If let's say you have a million data and each individual item in the list is like one megabytes or something, then yeah, it could go wrong. Okay, I think those were some pretty tough questions. Thanks for your talk. Really amazing stuff. It looks amazing. We still have a hour or so, I think there might be one of the slides on the pizza left. You can grab some and watch.


Welcome to Thermodynamics 6. In this video we explore the relation between heat capacity and the third law of thermodynamics. As we will see, the third law is intimately connected with quantum theory. Indeed, it was a primary motivation for the development of a quantum theory of matter. Let's think about what happens to the entropy of a system as its temperature approaches absolute zero. For an ideal monatomic gas, the Sacher-Tetrode equation gives the entropy as a function of temperature and volume. In the limit T goes to zero, the argument of the logarithm goes to zero, and the expression goes to minus infinity, a very strange result. We can argue that this result is not valid because gases cannot exist at very low temperatures, so the expression is not applicable in this limit. As we saw in the previous video, the Sacher-Tetrode equation accurately predicts the entropy of a monatomic gas. However, in general, when cooled, real gases will condense to a liquid and then freeze to a solid. The equation is not applicable to these states. Let's consider the problem from a more abstract thermodynamic point of view. Suppose we have a system at temperature T. We extract heat delta Q. This changes the system's entropy by ds equals minus delta Q over T. As heat is removed and the system temperature approaches absolute zero, it seems like the magnitude of these entropy increments should grow without bound, since the denominator approaches zero. So the entropy would tend toward minus infinity. Entropy equals Boltzmann's constant times the logarithm of gamma, the number of ways to arrange the components of the system. If S approaches minus infinity, then gamma would have to approach zero. But that makes no sense. The minimum possible value of gamma should be one. The system is in some arrangement, so there has to always be at least one way to arrange the components of a system. Let's look at this from a slightly different point of view. Recall the definition of heat capacity C. To change an object's temperature by dt, we have to add heat delta Q equal to C dt. In the present case, we are extracting heat, which is adding negative heat, so we have an additional minus sign. Then ds equals C over T dt. We see that the entropy increments will not blow up if the ratio C over T remains finite as T goes to zero. That is, if the heat capacity goes to zero, at least as fast as the temperature does. Let's now give one statement of the third law of thermodynamics. The entropy of a system approaches a constant value, which is zero in certain cases, as its temperature approaches absolute zero. From our present discussion, we see that a corollary of this is that the heat capacity of any system must approach zero as the temperature goes to zero. There is an intimate connection between heat capacity and the third law. Now, let's consider the heat capacity of solids, since that is the state we generally deal with at very low temperatures. In 1890, the Dullong-Petit law was proposed. Dullong and Petit noticed that the experimental heat capacity of many solids is near 25 joules per mole kelvin. For example, in the table at left are values for several metals at room temperature, ranging from 24.3 for aluminum to 26.4 for lead. Recall that one mole is Avogadro's number of molecules, about 6 times 10 to the 23rd. The plot at right shows molar heat capacity versus atomic number Z for most of the elements, which are solids at room temperature. The great majority of these values were unknown at the time of Dullong and Petit. Still, we see that, roughly speaking, the values do tend to cluster about the Dullong-Petit value, indicated by the horizontal red line.  If n is Avogadro's number, then nk is the gas constant r, 8.314 joules per mole kelvin, and the molar heat capacity is 12.47. The values for helium, neon, and argon gas agree with this prediction to four digits. The Dullong-Petit law predicts that many solids have a molar heat capacity about twice this. 3r equals 24.94 joules per mole kelvin. This leads us to ask, why do some solids have twice the molar heat capacity of some gases?  The balls can move, but the springs will tend to return them to their equilibrium positions in the crystal lattice. In addition to the kinetic energy due to the motion of the balls, the solids will also contain potential energy due to the compression and stretching of the springs. In the third video of the Mechanic Series, we saw that when a mass on a spring oscillates, the kinetic and potential energies of the system fluctuate sinusoidally, such that the average kinetic and potential energies are equal. So, an explanation for why some solids have twice the molar heat capacity of some gases is that in a solid, atoms store the same kinetic energy as they would in a gas state at the same temperature, but in addition the chemical bonds store an equal amount of potential energy. However, this higher heat capacity for a solid, like that of a monatomic gas, is independent of temperature. We still have the issue that the heat capacity should go to zero as the temperature does, so that the entropy at zero temperature remains finite. During the 19th century, the development of cryogenic technology enabled the measurement of heat capacity at very low temperatures. Researchers found that, as shown here for platinum, heat capacity does indeed approach zero as temperature does. Good news for the third law. And, notice that as temperature increases, the value approaches the do-long petty value of 25 Joules per mole Kelvin. But how do we explain this phenomenon? In 1907, the Einstein model provided an answer. Albert Einstein is, of course, famous for his theory of relativity, but his reputation as one of the greatest, arguably THE greatest, physicist, is due as much to his contributions to many other fields of physics, including thermodynamics. Starting with our balls connected by Spring's model of a solid, we treat each atom as a three-dimensional harmonic oscillator, able to oscillate independently in any of the three dimensions of space. In general, this is a difficult problem to analyze, because the force on each atom depends on the positions of its neighbors. So, the oscillations are coupled. Einstein made the simplifying assumption that these forces are due to the average or mean field of the other atoms. In this case, the atoms can be treated as moving independently. This is equivalent to having the springs connected to each atom in turn connected to fixed supports instead of to other atoms. This assumption avoids the problem of coupled oscillations. Now the oscillations of each atom in each dimension are independent and of the same frequency. And the thermal behavior of the entire solid is equivalent to three-n independent one-dimensional oscillators. Here's an atom oscillating in the single x dimension. Classically, this would be a sinusoidal function of time with some amplitude A and frequency nu determined by the atom's mass and the stiffness of the springs, the chemical bonds. Einstein's brilliant idea was to apply the, at that time, new quantum theory to this oscillator. Previously, quantum theory had only been applied to electromagnetic oscillations. In this theory, the energy of an electromagnetic field oscillating at frequency nu can only have the discrete values n h nu, where n is a non-negative integer and h is Planck's constant. Technically, there can also be an additive constant to the energy, but that won't concern us here. Einstein guessed that quantum theory might be a general principle of nature applying to any oscillations, even the mechanical oscillations of atoms in a solid. The constant h nu, a quantum of energy, can also be written as KTE, where K is Boltzmann's constant and TE is called the Einstein temperature. TE equals h nu over K. So the oscillator energy is assumed limited to the discrete values n KTE. In the previous video on statistical mechanics, we developed the Boltzmann distribution. This gives the occupation frequency f n of the oscillator state with energy n KTE as f n equals 1 over z e to the minus n KTE over KT. Canceling common k's, we are left with e to the minus n TE over T. The occupation frequency is the fraction of time a system will spend in a state with the given energy when the temperature is T. This can also be interpreted as the probability that the system will be in that state. For convenience, let's set a equal to e to the minus TE over T. This is less than 1. Then f n equals 1 over z a to the n. The occupation frequencies have to sum to 1 because the probability that the oscillator has any possible energy is 100%. This requires the normalizing factor z, the so-called partition function, to equal the sum from n equals 0 to infinity of a to the n. The sum evaluates to 1 over 1 minus a. Now we can calculate the average energy of the one dimensional quantum oscillator. This is the sum from n equals 0 to infinity, that is the sum over all possible energy states of f n, the probability of that state, times e n, the energy of that state. This is KTE over z times the sum of n a to the n. This sum evaluates to a over quantity 1 minus a squared. Substituting for a and simplifying, we get KTE over e to the TE over T minus 1. If we set KTE equal to 1 and call T over TE x, this has the functional form 1 over e to the 1 over x minus 1, with x proportional to temperature. Here's a plot of that function. For large x, large temperature, the function becomes a line. This is the classical result that the energy of a system is proportional to temperature. The slope of that line is the heat capacity, but for small x, low temperature, the curve flattens out. So the heat capacity goes to 0, as required by the third law and observed experimentally. For a solid of n atoms, each of which can oscillate independently in three dimensions, the average energy is 3n times our 1d result. So u equals 3n KTE over e to the TE over T minus 1. Let's look at the high temperature limit. T goes to infinity. In this case, TE over T goes to 0. Since e to a small exponent is well approximated by 1 plus the exponent, e to the TE over T can be replaced by 1 plus TE over T. The result is the system energy u reduces to 3n KT. The rate of change of u with respect to T is the heat capacity, C equals 3n K, the prediction of the Doulomb-Petit law. Now let's look at the low temperature limit. T goes to 0. In this case, TE over T goes to infinity. Since e to a very large exponent is a huge number, the denominator, e to the TE over T minus 1, is the rate of change of u with respect to TE over T minus 1 is essentially just e to the TE over T. Writing 1 over e to the TE over T as e to the minus TE over T, we find u goes to 3n KTE e to the minus TE over T. The slope or derivative of this function can be calculated with a computer algebra model. We find a heat capacity of 3n K, quantity TE over T squared, e to the minus TE over T. This goes to 0 as T goes to 0. For reference, the exact heat capacity of the Einstein model is given at top in blue. Here's the Einstein model compared to the observed heat capacity of platinum. The agreement is good for higher temperatures. At low temperatures, the Einstein model has qualitatively correct behavior, with heat capacity decreasing to 0, but it decreases too fast and fails to give quantitatively correct results. Still, it indicates that the reason heat capacity decreases to 0 with temperature is the quantum mechanical nature of matter. The reason why quantum theory predicts zero heat capacity at zero temperature is as follows. The entire solid is thermally equivalent to 3n one-dimensional quantum harmonic oscillators. The energy of a single oscillator can only be 0, KTE, 2KTE, and so on. At temperature T, the thermal energy available in a single interaction is on the order of KT. If T is much less than the Einstein temperature TE, then almost no interactions will have enough energy to excite an oscillator from its ground state to its first excited state with energy KTE. So the oscillators will generally not be able to absorb energy. This results in the entire solid generally not being able to absorb energy, which means its heat capacity is 0.